summaryrefslogtreecommitdiff
path: root/mrbgems/mruby-compiler/core
diff options
authorNobuhiro Iwamatsu <iwamatsu@debian.org>2026-06-30 16:07:15 +0900
committergit-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com>2026-06-30 16:34:09 +0000
commit7045fd64b743827a6c67eac54a81196f2cb9a3be (patch)
treef6e0de36aeee5f8cef19aa814027a917549abcff /mrbgems/mruby-compiler/core
parentb9bf429f92ff037e31812f9989fdb51add8c775a (diff)
Imported using git-ubuntu import.
Notes
Notes: * New upstream release. * Update d/patches: - Drop fix-bigint-on-raspberry-pi.patch - Drop CVE-2025-7207.patch * Update d/control: - Bumped Standards-Version to 4.7.4.1 - Remove redundant 'Rules-Requires-Root: no' field - Remove redundant 'Priority: optional' field
Diffstat (limited to 'mrbgems/mruby-compiler/core')
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c6835
-rw-r--r--mrbgems/mruby-compiler/core/node.h723
-rw-r--r--mrbgems/mruby-compiler/core/parse.y3651
-rw-r--r--mrbgems/mruby-compiler/core/y.tab.c16165
4 files changed, 24213 insertions, 3161 deletions
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c
index 357440d..48cae65 100644
--- a/mrbgems/mruby-compiler/core/codegen.c
+++ b/mrbgems/mruby-compiler/core/codegen.c
@@ -4,6 +4,41 @@
** See Copyright Notice in mruby.h
*/
+/*
+ * ## Code Generator
+ *
+ * This file implements the mruby code generator, a crucial component of the mruby
+ * compilation pipeline. Its primary responsibility is to translate the Abstract
+ * Syntax Tree (AST), produced by the parser, into mruby bytecode (Instruction
+ * Sequence - iseq).
+ *
+ * ### Key Operational Aspects:
+ *
+ * - **AST Traversal:** The generator walks through the AST nodes, processing each
+ * node type and emitting corresponding bytecode instructions.
+ * - **Scope Management:** It manages lexical scopes, keeping track of local
+ * variables, upvalues (variables from enclosing scopes), and register
+ * allocation within each scope. This is vital for correct variable access
+ * and lifetime.
+ * - **Opcode Generation:** For different AST node types (e.g., literals,
+ * arithmetic operations, control flow statements, method calls, variable
+ * assignments), specific opcodes are generated. This involves selecting the
+ * appropriate instruction and its operands.
+ * - **Loop Handling:** It provides mechanisms to correctly generate bytecode for
+ * various loop constructs (e.g., `while`, `for`, `until`), including managing
+ * `break`, `next`, and `redo` statements by patching jump addresses.
+ * - **Instruction Sequence (iseq):** The output of this process is an `mrb_irep`
+ * structure, which contains the generated instruction sequence (iseq), literal
+ * pools, symbol tables, and other metadata required for execution by the
+ * mruby virtual machine.
+ * - **Error Handling:** Includes mechanisms for reporting errors encountered
+ * during code generation, such as syntax errors not caught by the parser or
+ * semantic errors.
+ *
+ * This code generator is essential for transforming human-readable mruby code
+ * into a format that the mruby VM can execute efficiently.
+ */
+
#include <mruby.h>
#include <mruby/compile.h>
#include <mruby/proc.h>
@@ -11,7 +46,6 @@
#include <mruby/numeric.h>
#include <mruby/string.h>
#include <mruby/debug.h>
-#include <mruby/presym.h>
#include "node.h"
#include <mruby/opcode.h>
#include <mruby/re.h>
@@ -20,71 +54,87 @@
#include <string.h>
#include <mruby/internal.h>
+/* Wrappers for mruby's memory management functions. */
+#define mrbc_malloc(s) mrb_basic_alloc_func(NULL,(s)) /* Allocates memory. */
+#define mrbc_realloc(p,s) mrb_basic_alloc_func((p),(s)) /* Reallocates memory. */
+#define mrbc_free(p) mrb_basic_alloc_func((p),0) /* Frees memory. */
+
#ifndef MRB_CODEGEN_LEVEL_MAX
+/* Maximum recursion depth for the codegen function to prevent stack overflows. */
#define MRB_CODEGEN_LEVEL_MAX 256
#endif
+/* Maximum number of arguments for some opcodes like OP_SUPER or OP_ARGARY. */
#define MAXARG_S (1<<16)
+/* Macro to detect (0 . 0) separators in literal arrays */
+#define IS_LITERAL_DELIM(node) \
+ ((node) && (node)->car && \
+ (node)->car->car == NULL && \
+ (node)->car->cdr == NULL)
+
typedef mrb_ast_node node;
typedef struct mrb_parser_state parser_state;
+/* Represents the different kinds of loops or blocks encountered during code generation. */
enum looptype {
- LOOP_NORMAL,
- LOOP_BLOCK,
- LOOP_FOR,
- LOOP_BEGIN,
- LOOP_RESCUE,
+ LOOP_NORMAL, /* A standard loop construct like `while` or `until`. */
+ LOOP_BLOCK, /* A block or lambda. */
+ LOOP_FOR, /* A `for` loop. */
+ LOOP_BEGIN, /* A `begin...end` block (often with `rescue` or `ensure`). */
+ LOOP_RESCUE, /* The `rescue` part of a `begin...rescue...end` block. */
};
+/* Information about a loop currently being compiled, used for `break`, `next`, `redo`, etc. */
struct loopinfo {
- enum looptype type;
- uint32_t pc0; /* `next` destination */
- uint32_t pc1; /* `redo` destination */
- uint32_t pc2; /* `break` destination */
- int reg; /* destination register */
- struct loopinfo *prev;
+ enum looptype type; /* Type of the loop, using `enum looptype`. */
+ uint32_t pc0; /* Jump destination for `next`, or start of loop for `retry` in `rescue`. */
+ uint32_t pc1; /* Jump destination for `redo`. */
+ uint32_t pc2; /* Jump destination for `break`. */
+ int reg; /* Register to store the loop's return value (e.g., from `break val`), or -1 if no value. */
+ struct loopinfo *prev; /* Pointer to the previous `loopinfo` in a linked list (for nested loops). */
};
+/* Represents the state of the code generator for a particular lexical scope. */
typedef struct scope {
- mrb_state *mrb;
- mrb_mempool *mpool;
+ mrb_state *mrb; /* Pointer to the mruby state. */
+ mempool *mpool; /* Pointer to the memory pool for this scope's allocations. */
- struct scope *prev;
+ struct scope *prev; /* Pointer to the previous (enclosing) scope. */
- node *lv;
+ node *lv; /* AST node representing the list of local variables in this scope. */
- uint16_t sp;
- uint32_t pc;
- uint32_t lastpc;
- uint32_t lastlabel;
- uint16_t ainfo:15;
- mrb_bool mscope:1;
+ uint16_t sp; /* Current stack pointer (register index) within this scope. */
+ uint32_t pc; /* Current program counter (instruction index) for the ISEQ being generated. */
+ uint32_t lastpc; /* Program counter of the previously emitted instruction (used for peephole optimization). */
+ uint32_t lastlabel; /* Program counter of the last label emitted (inhibits some peephole optimizations). */
+ uint16_t ainfo:15; /* Argument information bitfield (counts for req, opt, rest, post, key, kdict, block). */
+ mrb_bool mscope:1; /* Boolean flag: true if this is a method/module/class scope (not a block). */
- struct loopinfo *loop;
- mrb_sym filename_sym;
- uint16_t lineno;
+ struct loopinfo *loop; /* Pointer to the current innermost `loopinfo` structure for this scope. */
+ mrb_sym filename_sym; /* `mrb_sym` representing the current filename. */
+ uint16_t lineno; /* Current line number being processed. */
- mrb_code *iseq;
- uint16_t *lines;
- uint32_t icapa;
+ mrb_code *iseq; /* Pointer to the dynamically growing array of `mrb_code` (instructions). */
+ uint16_t *lines; /* Array to store line numbers corresponding to each instruction (for debugging). */
+ uint32_t icapa; /* Current capacity of the `iseq` and `lines` arrays. */
- mrb_irep *irep;
- mrb_irep_pool *pool;
- mrb_sym *syms;
- mrb_irep **reps;
- struct mrb_irep_catch_handler *catch_table;
- uint32_t pcapa, scapa, rcapa;
+ mrb_irep *irep; /* Pointer to the `mrb_irep` (instruction sequence representation) being built. */
+ mrb_irep_pool *pool; /* Pointer to the literal pool for the `irep`. */
+ mrb_sym *syms; /* Pointer to the symbol list for the `irep`. */
+ mrb_irep **reps; /* Pointer to the array of child `irep`s (for nested blocks/methods). */
+ struct mrb_irep_catch_handler *catch_table; /* Pointer to the table of catch handlers for this scope. */
+ uint32_t pcapa, scapa, rcapa; /* Current capacities of the `pool`, `syms`, and `reps` arrays respectively. */
- uint16_t nlocals;
- uint16_t nregs;
- int ai;
+ uint16_t nlocals; /* Number of local variables in this scope. */
+ uint16_t nregs; /* Number of registers used in this scope (maximum value of `sp`). */
+ int ai; /* Arena index for mruby's garbage collector. */
- int debug_start_pos;
- uint16_t filename_index;
- parser_state* parser;
+ int debug_start_pos; /* Starting ISEQ position for the current debug file information. */
+ uint16_t filename_index; /* Index of the current filename in the parser's filename table. */
+ parser_state* parser; /* Pointer to the `mrb_parser_state`. */
- int rlev; /* recursion levels */
+ int rlev; /* Recursion level counter for `codegen` calls, to prevent stack overflow. */
} codegen_scope;
static codegen_scope* scope_new(mrb_state *mrb, codegen_scope *prev, node *lv);
@@ -102,12 +152,30 @@ static void loop_pop(codegen_scope *s, int val);
static int catch_handler_new(codegen_scope *s);
static void catch_handler_set(codegen_scope *s, int ent, enum mrb_catch_type type, uint32_t begin, uint32_t end, uint32_t target);
-static void gen_assignment(codegen_scope *s, node *tree, node *rhs, int sp, int val);
static void gen_massignment(codegen_scope *s, node *tree, int sp, int val);
+static void codegen_masgn(codegen_scope *s, node *varnode, node *rhs, int sp, int val);
+static void gen_assignment(codegen_scope *s, node *tree, node *rhs, int sp, int val);
+static void codegen_call_assign(codegen_scope *s, node *varnode, node *rhs, int sp, int val);
static void codegen(codegen_scope *s, node *tree, int val);
static void raise_error(codegen_scope *s, const char *msg);
+/* Forward declarations for helper functions */
+static struct mrb_ast_var_header* get_var_header(node *n);
+
+/* NULL-safe node type accessor macro */
+#define node_type(n) ((n) ? NODE_TYPE(n) : (enum node_type)0)
+
+/*
+ * Reports a compilation error encountered during code generation.
+ *
+ * This function formats an error message, typically including the filename
+ * and line number where the error occurred. It then triggers a longjmp
+ * to unwind the compilation process, effectively halting further code generation.
+ *
+ * @param s The current code generation scope.
+ * @param message The error message string.
+ */
static void
codegen_error(codegen_scope *s, const char *message)
{
@@ -124,50 +192,64 @@ codegen_error(codegen_scope *s, const char *message)
while (s->prev) {
codegen_scope *tmp = s->prev;
if (s->irep) {
- mrb_free(s->mrb, s->iseq);
+ mrbc_free(s->iseq);
for (int i=0; i<s->irep->plen; i++) {
mrb_irep_pool *p = &s->pool[i];
if ((p->tt & 0x3) == IREP_TT_STR || p->tt == IREP_TT_BIGINT) {
- mrb_free(s->mrb, (void*)p->u.str);
+ mrbc_free((void*)p->u.str);
}
}
- mrb_free(s->mrb, s->pool);
- mrb_free(s->mrb, s->syms);
- mrb_free(s->mrb, s->catch_table);
+ mrbc_free(s->pool);
+ mrbc_free(s->syms);
+ mrbc_free(s->catch_table);
if (s->reps) {
/* copied from mrb_irep_free() in state.c */
for (int i=0; i<s->irep->rlen; i++) {
if (s->reps[i])
mrb_irep_decref(s->mrb, (mrb_irep*)s->reps[i]);
}
- mrb_free(s->mrb, s->reps);
+ mrbc_free(s->reps);
}
- mrb_free(s->mrb, s->lines);
+ mrbc_free(s->lines);
}
- mrb_mempool_close(s->mpool);
+ mempool_close(s->mpool);
s = tmp;
}
MRB_THROW(s->mrb->jmp);
}
+/*
+ * Allocates memory from the memory pool associated with the current codegen_scope.
+ *
+ * This function is used for allocations that are expected to have the same
+ * lifetime as the current scope. The memory allocated via this function will be
+ * freed automatically when the scope is finished and its memory pool is closed.
+ * It calls `codegen_error` if allocation fails.
+ *
+ * @param s The current code generation scope.
+ * @param len The number of bytes to allocate.
+ * @return A pointer to the allocated memory.
+ */
static void*
codegen_palloc(codegen_scope *s, size_t len)
{
- void *p = mrb_mempool_alloc(s->mpool, len);
+ void *p = mempool_alloc(s->mpool, len);
if (!p) codegen_error(s, "pool memory allocation");
return p;
}
-static void*
-codegen_realloc(codegen_scope *s, void *p, size_t len)
-{
- p = mrb_realloc_simple(s->mrb, p, len);
-
- if (!p && len > 0) codegen_error(s, "mrb_realloc");
- return p;
-}
-
+/*
+ * Checks if instruction operands `a` or `b` exceed 8 bits (0xff).
+ *
+ * If the parser option `no_ext_ops` is set (disallowing OP_EXT1/2/3),
+ * and either operand is larger than 0xff, this function calls `codegen_error`
+ * to report that an extended opcode would be required.
+ *
+ * @param s The current code generation scope.
+ * @param a The first operand.
+ * @param b The second operand.
+ */
static void
check_no_ext_ops(codegen_scope *s, uint16_t a, uint16_t b)
{
@@ -176,12 +258,35 @@ check_no_ext_ops(codegen_scope *s, uint16_t a, uint16_t b)
}
}
+/*
+ * Creates a new label by returning the current program counter (pc)
+ * and updating `s->lastlabel` to this value.
+ *
+ * Marking a PC as a label (`s->lastlabel = s->pc`) can inhibit certain
+ * peephole optimizations that might otherwise modify instructions at this label.
+ *
+ * @param s The current code generation scope.
+ * @return The current program counter, which is now marked as a label.
+ */
static int
new_label(codegen_scope *s)
{
return s->lastlabel = s->pc;
}
+/*
+ * Emits a single byte (`i`) into the instruction sequence (`s->iseq`)
+ * at the specified program counter (`pc`).
+ *
+ * This function handles dynamic resizing of the `iseq` buffer and the
+ * associated `lines` array (if line number tracking is enabled).
+ * It also records the current line number (`s->lineno`) for the emitted
+ * instruction in `s->lines[pc]`.
+ *
+ * @param s The current code generation scope.
+ * @param pc The program counter where the byte should be emitted.
+ * @param i The byte to emit.
+ */
static void
emit_B(codegen_scope *s, uint32_t pc, uint8_t i)
{
@@ -195,9 +300,9 @@ emit_B(codegen_scope *s, uint32_t pc, uint8_t i)
else {
s->icapa *= 2;
}
- s->iseq = (mrb_code*)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa);
+ s->iseq = (mrb_code*)mrbc_realloc(s->iseq, sizeof(mrb_code)*s->icapa);
if (s->lines) {
- s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->icapa);
+ s->lines = (uint16_t*)mrbc_realloc(s->lines, sizeof(uint16_t)*s->icapa);
}
}
if (s->lines) {
@@ -209,6 +314,15 @@ emit_B(codegen_scope *s, uint32_t pc, uint8_t i)
s->iseq[pc] = i;
}
+/*
+ * Emits a 2-byte short integer (`i`) into the instruction sequence at `pc`.
+ * The short is emitted in big-endian format (most significant byte first).
+ * This is achieved by calling `emit_B` twice.
+ *
+ * @param s The current code generation scope.
+ * @param pc The program counter where the short should be emitted.
+ * @param i The 2-byte short to emit.
+ */
static void
emit_S(codegen_scope *s, int pc, uint16_t i)
{
@@ -219,6 +333,13 @@ emit_S(codegen_scope *s, int pc, uint16_t i)
emit_B(s, pc+1, lo);
}
+/*
+ * Generates (emits) a single byte (`i`) at the current program counter (`s->pc`)
+ * and then increments `s->pc` by 1.
+ *
+ * @param s The current code generation scope.
+ * @param i The byte to emit.
+ */
static void
gen_B(codegen_scope *s, uint8_t i)
{
@@ -226,6 +347,13 @@ gen_B(codegen_scope *s, uint8_t i)
s->pc++;
}
+/*
+ * Generates (emits) a 2-byte short integer (`i`) at the current program
+ * counter (`s->pc`) and then increments `s->pc` by 2.
+ *
+ * @param s The current code generation scope.
+ * @param i The 2-byte short to emit.
+ */
static void
gen_S(codegen_scope *s, uint16_t i)
{
@@ -233,6 +361,13 @@ gen_S(codegen_scope *s, uint16_t i)
s->pc += 2;
}
+/*
+ * Generates an opcode `i` that takes no operands.
+ * Updates `s->lastpc` to the current `s->pc` before emitting.
+ *
+ * @param s The current code generation scope.
+ * @param i The opcode to generate.
+ */
static void
genop_0(codegen_scope *s, mrb_code i)
{
@@ -240,6 +375,16 @@ genop_0(codegen_scope *s, mrb_code i)
gen_B(s, i);
}
+/*
+ * Generates an opcode `i` with a single 16-bit operand `a`.
+ * If `a` is larger than 0xFF (255), it prepends `OP_EXT1` and emits `a` as a short.
+ * Otherwise, it emits `a` as a single byte.
+ * Updates `s->lastpc`.
+ *
+ * @param s The current code generation scope.
+ * @param i The opcode to generate.
+ * @param a The 16-bit operand.
+ */
static void
genop_1(codegen_scope *s, mrb_code i, uint16_t a)
{
@@ -256,6 +401,17 @@ genop_1(codegen_scope *s, mrb_code i, uint16_t a)
}
}
+/*
+ * Generates an opcode `i` with two 16-bit operands `a` and `b`.
+ * It handles operand extensions (`OP_EXT1`, `OP_EXT2`, `OP_EXT3`)
+ * based on whether `a` and/or `b` are larger than 0xFF.
+ * Updates `s->lastpc`.
+ *
+ * @param s The current code generation scope.
+ * @param i The opcode to generate.
+ * @param a The first 16-bit operand.
+ * @param b The second 16-bit operand.
+ */
static void
genop_2(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b)
{
@@ -286,6 +442,18 @@ genop_2(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b)
}
}
+/*
+ * Generates an opcode `i` with three operands `a`, `b`, and `c`.
+ * It uses `genop_2` to emit `i`, `a`, and `b` (handling extensions for `a` and `b`),
+ * and then emits `c` as a single byte using `gen_B`. `c` is assumed to fit in a byte.
+ * Updates `s->lastpc` (via `genop_2`).
+ *
+ * @param s The current code generation scope.
+ * @param i The opcode to generate.
+ * @param a The first 16-bit operand.
+ * @param b The second 16-bit operand.
+ * @param c The third 16-bit operand (emitted as a byte).
+ */
static void
genop_3(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b, uint16_t c)
{
@@ -293,6 +461,17 @@ genop_3(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b, uint16_t c)
gen_B(s, (uint8_t)c);
}
+/*
+ * Generates an opcode `i` with a 16-bit operand `a` and a 16-bit operand `b`.
+ * Operand `a` is emitted using `genop_1` (which handles `OP_EXT1` if needed).
+ * Operand `b` is emitted as a 2-byte short using `gen_S`.
+ * Updates `s->lastpc` (via `genop_1`).
+ *
+ * @param s The current code generation scope.
+ * @param i The opcode to generate.
+ * @param a The first 16-bit operand.
+ * @param b The second 16-bit operand (emitted as a short).
+ */
static void
genop_2S(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b)
{
@@ -300,6 +479,17 @@ genop_2S(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b)
gen_S(s, b);
}
+/*
+ * Generates an opcode `i` with a 16-bit operand `a` and a 32-bit operand `b`.
+ * Operand `a` is emitted using `genop_1` (handling `OP_EXT1`).
+ * Operand `b` is emitted as two 2-byte shorts (high word then low word).
+ * Updates `s->lastpc` (via `genop_1`).
+ *
+ * @param s The current code generation scope.
+ * @param i The opcode to generate.
+ * @param a The first 16-bit operand.
+ * @param b The 32-bit operand (emitted as two shorts).
+ */
static void
genop_2SS(codegen_scope *s, mrb_code i, uint16_t a, uint32_t b)
{
@@ -308,6 +498,15 @@ genop_2SS(codegen_scope *s, mrb_code i, uint16_t a, uint32_t b)
gen_S(s, b&0xffff);
}
+/*
+ * Generates an opcode `i` followed by a 3-byte "wide" operand `a`.
+ * The 3-byte operand is emitted as three separate bytes (a1, a2, a3).
+ * Updates `s->lastpc`.
+ *
+ * @param s The current code generation scope.
+ * @param i The opcode to generate.
+ * @param a The 32-bit operand, of which the lower 24 bits are used.
+ */
static void
genop_W(codegen_scope *s, mrb_code i, uint32_t a)
{
@@ -322,6 +521,7 @@ genop_W(codegen_scope *s, mrb_code i, uint32_t a)
gen_B(s, a3);
}
+/* Indicates whether a codegen function should produce a value on the stack (VAL) or not (NOVAL). */
#define NOVAL 0
#define VAL 1
@@ -333,6 +533,19 @@ no_optimize(codegen_scope *s)
return FALSE;
}
+/*
+ * Decodes a mruby bytecode instruction starting at the given program counter `pc`.
+ *
+ * It reads the opcode and its operands from the bytecode stream and populates
+ * a `mrb_insn_data` structure. This function handles standard opcodes as well
+ * as extended opcodes (OP_EXT1, OP_EXT2, OP_EXT3) to correctly parse operands
+ * of varying sizes. This is primarily used by the peephole optimizer and
+ * instruction analysis utilities.
+ *
+ * @param pc Pointer to the start of the instruction in the bytecode.
+ * @return A `mrb_insn_data` struct containing the decoded instruction,
+ * its operands (a, b, c), and the original address.
+ */
struct mrb_insn_data
mrb_decode_insn(const mrb_code *pc)
{
@@ -444,6 +657,19 @@ static uint8_t mrb_insn_size3[] = {
#undef BSS
#undef OPCODE
+/*
+ * Finds the program counter (PC) of the instruction immediately preceding
+ * the instruction at the given `pc`.
+ *
+ * It iterates backward through the already generated instruction sequence (`s->iseq`)
+ * from its beginning up to `pc`, decoding each instruction to determine its size
+ * and thus find the start of the previous instruction.
+ *
+ * @param s The current code generation scope.
+ * @param pc Pointer to an instruction in `s->iseq`.
+ * @return Pointer to the start of the instruction preceding the one at `pc`,
+ * or NULL if `pc` is at the beginning of `s->iseq`.
+ */
static const mrb_code*
mrb_prev_pc(codegen_scope *s, const mrb_code *pc)
{
@@ -471,10 +697,22 @@ mrb_prev_pc(codegen_scope *s, const mrb_code *pc)
return prev_pc;
}
+/* Gets the memory address of the current instruction pointed to by the program counter (pc). */
#define pc_addr(s) &((s)->iseq[(s)->pc])
+/* Converts an instruction memory address to a program counter (pc) offset. */
#define addr_pc(s, addr) (uint32_t)((addr) - s->iseq)
+/* Resets the program counter (pc) to the address of the previously generated instruction. Used in peephole optimizations. */
#define rewind_pc(s) s->pc = s->lastpc
+/*
+ * Decodes and returns the last instruction that was emitted into the
+ * instruction sequence (`s->iseq`).
+ * It uses `mrb_decode_insn` on the instruction at `s->iseq[s->lastpc]`.
+ * If no instructions have been emitted (`s->pc == 0`), it returns a NOP.
+ *
+ * @param s The current code generation scope.
+ * @return A `mrb_insn_data` struct for the last emitted instruction.
+ */
static struct mrb_insn_data
mrb_last_insn(codegen_scope *s)
{
@@ -485,14 +723,40 @@ mrb_last_insn(codegen_scope *s)
return mrb_decode_insn(&s->iseq[s->lastpc]);
}
+/*
+ * Determines if peephole optimizations should be disabled for the current instruction.
+ * Peephole optimization is disabled if:
+ * - General optimization is off (`no_optimize(s)` is true).
+ * - The current program counter (`s->pc`) is the target of a label (`s->lastlabel == s->pc`).
+ * - It's the beginning of the bytecode (`s->pc == 0`).
+ * - The current PC is the same as the PC of the last emitted instruction (`s->pc == s->lastpc`),
+ * which can happen after a `rewind_pc`.
+ *
+ * @param s The current code generation scope.
+ * @return TRUE if peephole optimizations should be skipped, FALSE otherwise.
+ */
static mrb_bool
no_peephole(codegen_scope *s)
{
return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0 || s->pc == s->lastpc;
}
+/* Sentinel value for jump offsets that are not yet determined and need to be linked later. */
#define JMPLINK_START UINT32_MAX
+/*
+ * Generates the 2-byte signed offset for a jump instruction.
+ *
+ * The `pc` argument is the absolute target program counter for the jump.
+ * The function calculates the relative offset from the instruction *after*
+ * the current jump instruction (i.e., `s->pc + 2` for the jump opcode and its offset)
+ * to the target `pc`. This offset is then emitted as a 16-bit signed integer.
+ * If the offset is too large to fit in 16 bits, it calls `codegen_error`.
+ * If `pc` is `JMPLINK_START`, it emits an offset of 0 (placeholder for later patching).
+ *
+ * @param s The current code generation scope.
+ * @param pc The absolute target program counter for the jump.
+ */
static void
gen_jmpdst(codegen_scope *s, uint32_t pc)
{
@@ -509,6 +773,18 @@ gen_jmpdst(codegen_scope *s, uint32_t pc)
gen_S(s, (uint16_t)off);
}
+/*
+ * Generates an unconditional jump instruction `i` (e.g., OP_JMP)
+ * that jumps to the absolute target program counter `pc`.
+ *
+ * It first emits the jump opcode `i` using `genop_0`, then emits
+ * the calculated jump offset using `gen_jmpdst`.
+ *
+ * @param s The current code generation scope.
+ * @param i The jump opcode to generate (e.g., OP_JMP).
+ * @param pc The absolute target program counter.
+ * @return The program counter where the jump offset was written. This is used for jump linking.
+ */
static uint32_t
genjmp(codegen_scope *s, mrb_code i, uint32_t pc)
{
@@ -522,6 +798,32 @@ genjmp(codegen_scope *s, mrb_code i, uint32_t pc)
#define genjmp_0(s,i) genjmp(s,i,JMPLINK_START)
+/*
+ * Generates a conditional jump instruction `i` (e.g., OP_JMPNOT, OP_JMPIF)
+ * based on the value in register `a`, targeting the absolute program counter `pc`.
+ *
+ * This function includes several peephole optimizations:
+ * - If the last instruction was a MOVE to register `a` from another temporary register,
+ * it rewinds and uses the source of the MOVE as the condition register.
+ * - If the last instruction loaded a constant (nil, false, true, integer) into register `a`,
+ * it may optimize the jump:
+ * - If the condition is known at compile time (e.g., JMPNOT after LOADF), it can
+ * transform the conditional jump into an unconditional OP_JMP.
+ * - If the condition is known and makes the jump always/never taken, it can
+ * remove the jump entirely (returning JMPLINK_START to signify this).
+ * The `val` parameter influences these optimizations: if `val` is false (NOVAL),
+ * it implies the preceding instruction producing `a` might be removable if the jump
+ * itself is optimized away.
+ *
+ * @param s The current code generation scope.
+ * @param i The conditional jump opcode.
+ * @param a The register index holding the condition value.
+ * @param pc The absolute target program counter for the jump.
+ * @param val Indicates if the value in register `a` from a previous instruction is needed
+ * beyond this conditional jump.
+ * @return The program counter where the jump offset was written, or `JMPLINK_START` if the
+ * jump was optimized away.
+ */
static uint32_t
genjmp2(codegen_scope *s, mrb_code i, uint16_t a, uint32_t pc, int val)
{
@@ -538,7 +840,7 @@ genjmp2(codegen_scope *s, mrb_code i, uint16_t a, uint32_t pc, int val)
}
break;
case OP_LOADNIL:
- case OP_LOADF:
+ case OP_LOADFALSE:
if (data.a == a || data.a > s->nlocals) {
s->pc = addr_pc(s, data.addr);
if (i == OP_JMPNOT || (i == OP_JMPNIL && data.insn == OP_LOADNIL)) {
@@ -549,7 +851,7 @@ genjmp2(codegen_scope *s, mrb_code i, uint16_t a, uint32_t pc, int val)
}
}
break;
- case OP_LOADT: case OP_LOADI8: case OP_LOADINEG: case OP_LOADI__1:
+ case OP_LOADTRUE: case OP_LOADI8: case OP_LOADINEG: case OP_LOADI__1:
case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3:
case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7:
if (data.a == a || data.a > s->nlocals) {
@@ -585,12 +887,34 @@ genjmp2(codegen_scope *s, mrb_code i, uint16_t a, uint32_t pc, int val)
static mrb_bool get_int_operand(codegen_scope *s, struct mrb_insn_data *data, mrb_int *ns);
static void gen_int(codegen_scope *s, uint16_t dst, mrb_int i);
+/*
+ * Generates an OP_MOVE instruction to copy the value from register `src` to register `dst`.
+ *
+ * This function incorporates several peephole optimizations to avoid redundant moves or
+ * to combine the move with preceding operations:
+ * - If `dst` and `src` are the same, the function does nothing.
+ * - If the previous instruction was also an `OP_MOVE` involving `src` or `dst`,
+ * it might combine or reorder them to eliminate redundant operations.
+ * - If the previous instruction loaded a literal (nil, self, true, false, integer,
+ * symbol, string, etc.) into `src`, and `src` is a temporary register,
+ * this function can rewind the program counter and generate the load operation
+ * directly into `dst`, effectively eliminating the `OP_MOVE`.
+ * - It can also perform constant folding for `OP_ADDI`/`OP_SUBI` if a sequence of
+ * `LOADI`, `MOVE`, `ADDI`/`SUBI` can be resolved at compile time.
+ *
+ * The `nopeep` parameter, if true, disables these peephole optimizations, forcing
+ * the generation of a direct `OP_MOVE` instruction.
+ *
+ * @param s The current code generation scope.
+ * @param dst The destination register index.
+ * @param src The source register index.
+ * @param nopeep If non-zero, disables peephole optimizations for this move.
+ */
static void
gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep)
{
- if (nopeep || no_peephole(s)) goto normal;
- else if (dst == src) return;
- else {
+ if (dst == src) return;
+ if (!(nopeep || no_peephole(s))) {
struct mrb_insn_data data = mrb_last_insn(s);
switch (data.insn) {
@@ -599,7 +923,7 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep)
if (data.a == src) {
if (data.b == dst) /* skip swapping MOVE */
return;
- if (data.a < s->nlocals) goto normal;
+ if (data.a < s->nlocals) break;
rewind_pc(s);
s->lastpc = addr_pc(s, mrb_prev_pc(s, data.addr));
gen_move(s, dst, data.b, FALSE);
@@ -611,34 +935,34 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep)
gen_move(s, dst, src, FALSE);
return;
}
- goto normal;
- case OP_LOADNIL: case OP_LOADSELF: case OP_LOADT: case OP_LOADF:
+ break;
+ case OP_LOADNIL: case OP_LOADSELF: case OP_LOADTRUE: case OP_LOADFALSE:
case OP_LOADI__1:
case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3:
case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7:
- if (data.a != src || data.a < s->nlocals) goto normal;
+ if (data.a != src || data.a < s->nlocals) break;
rewind_pc(s);
genop_1(s, data.insn, dst);
return;
case OP_HASH:
- if (data.b != 0) goto normal;
+ if (data.b != 0) break;
/* fall through */
case OP_LOADI8: case OP_LOADINEG:
case OP_LOADL: case OP_LOADSYM:
case OP_GETGV: case OP_GETSV: case OP_GETIV: case OP_GETCV:
case OP_GETCONST: case OP_STRING:
case OP_LAMBDA: case OP_BLOCK: case OP_METHOD: case OP_BLKPUSH:
- if (data.a != src || data.a < s->nlocals) goto normal;
+ if (data.a != src || data.a < s->nlocals) break;
rewind_pc(s);
genop_2(s, data.insn, dst, data.b);
return;
case OP_LOADI16:
- if (data.a != src || data.a < s->nlocals) goto normal;
+ if (data.a != src || data.a < s->nlocals) break;
rewind_pc(s);
genop_2S(s, data.insn, dst, data.b);
return;
case OP_LOADI32:
- if (data.a != src || data.a < s->nlocals) goto normal;
+ if (data.a != src || data.a < s->nlocals) break;
else {
uint32_t i = (uint32_t)data.b<<16|data.c;
rewind_pc(s);
@@ -646,7 +970,7 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep)
}
return;
case OP_ARRAY:
- if (data.a != src || data.a < s->nlocals || data.a < dst) goto normal;
+ if (data.a != src || data.a < s->nlocals || data.a < dst) break;
rewind_pc(s);
if (data.b == 0 || dst == data.a)
genop_2(s, OP_ARRAY, dst, 0);
@@ -654,49 +978,92 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep)
genop_3(s, OP_ARRAY2, dst, data.a, data.b);
return;
case OP_ARRAY2:
- if (data.a != src || data.a < s->nlocals || data.a < dst) goto normal;
+ if (data.a != src || data.a < s->nlocals || data.a < dst) break;
rewind_pc(s);
genop_3(s, OP_ARRAY2, dst, data.b, data.c);
return;
case OP_AREF:
case OP_GETUPVAR:
- if (data.a != src || data.a < s->nlocals) goto normal;
+ if (data.a != src || data.a < s->nlocals) break;
rewind_pc(s);
genop_3(s, data.insn, dst, data.b, data.c);
return;
case OP_ADDI: case OP_SUBI:
- if (addr_pc(s, data.addr) == s->lastlabel || data.a != src || data.a < s->nlocals) goto normal;
+ if (addr_pc(s, data.addr) == s->lastlabel || data.a != src || data.a < s->nlocals) break;
else {
struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr));
- if (data0.insn != OP_MOVE || data0.a != data.a || data0.b != dst) goto normal;
- s->pc = addr_pc(s, data0.addr);
+ if (data0.insn != OP_MOVE || data0.a != data.a || data0.b != dst) break;
if (addr_pc(s, data0.addr) != s->lastlabel) {
/* constant folding */
- data0 = mrb_decode_insn(mrb_prev_pc(s, data0.addr));
+ struct mrb_insn_data data1 = mrb_decode_insn(mrb_prev_pc(s, data0.addr));
mrb_int n;
- if (data0.a == dst && get_int_operand(s, &data0, &n)) {
+ if (data1.a == dst && get_int_operand(s, &data1, &n)) {
if ((data.insn == OP_ADDI && !mrb_int_add_overflow(n, data.b, &n)) ||
(data.insn == OP_SUBI && !mrb_int_sub_overflow(n, data.b, &n))) {
- s->pc = addr_pc(s, data0.addr);
+ s->pc = addr_pc(s, data1.addr);
gen_int(s, dst, n);
return;
}
}
}
+ /* ADDILV/SUBILV fusion: MOVE temp local; ADDI temp imm; MOVE local temp */
+ /* -> ADDILV local temp imm (temp is working space for method fallback) */
+ s->pc = addr_pc(s, data0.addr);
+ genop_3(s, data.insn == OP_ADDI ? OP_ADDILV : OP_SUBILV, dst, data.a, data.b);
+ return;
}
- genop_2(s, data.insn, dst, data.b);
- return;
+ break;
default:
break;
}
}
- normal:
+
genop_2(s, OP_MOVE, dst, src);
return;
}
+/*
+ * Searches for a local variable `id` in outer lexical scopes (upvalues).
+ *
+ * It first traverses the chain of enclosing `codegen_scope` structures
+ * (linked by `s->prev`). If not found, it then traverses the chain of
+ * `upper` RProc structures stored in the parser state.
+ *
+ * If the variable `id` is found in an outer scope:
+ * - It returns `lv`, the number of lexical levels (scopes) to go up
+ * to find the variable.
+ * - It sets the `*idx` output parameter to the variable's index within
+ * that outer scope's local variable table.
+ *
+ * If the variable is not found in any outer scope, it calls `codegen_error`
+ * to report an error (e.g., "No anonymous block parameter", "Can't find local variables").
+ *
+ * @param s The current code generation scope from which the search begins.
+ * @param id The `mrb_sym` (symbol) of the local variable to search for.
+ * @param idx Output parameter: pointer to an integer where the index of the
+ * variable in its defining scope will be stored.
+ * @return The lexical distance (number of scopes upwards) to the variable's
+ * defining scope.
+ */
static int search_upvar(codegen_scope *s, mrb_sym id, int *idx);
+/*
+ * Generates an `OP_GETUPVAR` instruction to retrieve an upvalue.
+ *
+ * The upvalue `id` is first located using `search_upvar` to determine its
+ * lexical level (`lv`) and index (`idx`) within that outer scope.
+ * Then, an `OP_GETUPVAR` instruction is generated to load this upvalue
+ * into the destination register `dst`.
+ *
+ * Peephole Optimization:
+ * - If the immediately preceding instruction was an `OP_SETUPVAR` for the
+ * same upvalue (`id`), lexical level (`lv`), and destination register (`dst`),
+ * this `OP_GETUPVAR` is skipped as the value is already in the target register.
+ *
+ * @param s The current code generation scope.
+ * @param dst The destination register index where the upvalue will be loaded.
+ * @param id The `mrb_sym` (symbol) of the upvalue to retrieve.
+ */
static void
gen_getupvar(codegen_scope *s, uint16_t dst, mrb_sym id)
{
@@ -713,6 +1080,24 @@ gen_getupvar(codegen_scope *s, uint16_t dst, mrb_sym id)
genop_3(s, OP_GETUPVAR, dst, idx, lv);
}
+/*
+ * Generates an `OP_SETUPVAR` instruction to set an upvalue.
+ *
+ * The upvalue `id` is first located using `search_upvar` to determine its
+ * lexical level (`lv`) and index (`idx`) within that outer scope.
+ * Then, an `OP_SETUPVAR` instruction is generated to set this upvalue
+ * using the value from register `dst`.
+ *
+ * Peephole Optimization:
+ * - If the immediately preceding instruction was an `OP_MOVE` where register `dst`
+ * was the destination (`data.a == dst`), this function will rewind the program
+ * counter and use the source register of that `OP_MOVE` (`data.b`) as the source
+ * for `OP_SETUPVAR` instead. This effectively uses the original value before the move.
+ *
+ * @param s The current code generation scope.
+ * @param dst The register index holding the value to set the upvalue to.
+ * @param id The `mrb_sym` (symbol) of the upvalue to set.
+ */
static void
gen_setupvar(codegen_scope *s, uint16_t dst, mrb_sym id)
{
@@ -729,6 +1114,24 @@ gen_setupvar(codegen_scope *s, uint16_t dst, mrb_sym id)
genop_3(s, OP_SETUPVAR, dst, idx, lv);
}
+/*
+ * Generates a return instruction (e.g., `OP_RETURN`, `OP_RETURN_BLK`).
+ *
+ * This function emits the specified return opcode `op` with the source register `src`
+ * containing the value to be returned.
+ *
+ * Peephole Optimization:
+ * - If peephole optimization is enabled and the immediately preceding instruction
+ * was an `OP_MOVE` into the `src` register (`data.insn == OP_MOVE && src == data.a`),
+ * this function will rewind the program counter and generate the return instruction
+ * using the original source register of that `OP_MOVE` (`data.b`). This avoids
+ * a redundant move before returning.
+ * - It also avoids emitting multiple consecutive `OP_RETURN` instructions.
+ *
+ * @param s The current code generation scope.
+ * @param op The specific return opcode to generate (e.g., `OP_RETURN`, `OP_RETURN_BLK`).
+ * @param src The register index holding the value to be returned.
+ */
static void
gen_return(codegen_scope *s, uint8_t op, uint16_t src)
{
@@ -742,12 +1145,50 @@ gen_return(codegen_scope *s, uint8_t op, uint16_t src)
rewind_pc(s);
genop_1(s, op, data.b);
}
- else if (data.insn != OP_RETURN) {
+ else if (data.insn == OP_LOADSELF && src == data.a && op == OP_RETURN) {
+ /* LOADSELF + RETURN -> RETSELF */
+ rewind_pc(s);
+ genop_0(s, OP_RETSELF);
+ }
+ else if (data.insn == OP_LOADNIL && src == data.a && op == OP_RETURN) {
+ /* LOADNIL + RETURN -> RETNIL */
+ rewind_pc(s);
+ genop_0(s, OP_RETNIL);
+ }
+ else if (data.insn == OP_LOADTRUE && src == data.a && op == OP_RETURN) {
+ /* LOADTRUE + RETURN -> RETTRUE */
+ rewind_pc(s);
+ genop_0(s, OP_RETTRUE);
+ }
+ else if (data.insn == OP_LOADFALSE && src == data.a && op == OP_RETURN) {
+ /* LOADFALSE + RETURN -> RETFALSE */
+ rewind_pc(s);
+ genop_0(s, OP_RETFALSE);
+ }
+ else if (data.insn != OP_RETURN && data.insn != OP_RETSELF && data.insn != OP_RETNIL &&
+ data.insn != OP_RETTRUE && data.insn != OP_RETFALSE) {
genop_1(s, op, src);
}
}
}
+/*
+ * Attempts to extract a compile-time integer value from a given instruction.
+ *
+ * This function checks if the instruction described by `data` is one of
+ * the integer loading opcodes (e.g., `OP_LOADI__1`, `OP_LOADINEG`, `OP_LOADI_0`
+ * through `OP_LOADI_7`, `OP_LOADI8`, `OP_LOADI16`, `OP_LOADI32`) or `OP_LOADL`
+ * where the literal pool entry is an integer.
+ *
+ * If successful, it stores the extracted integer value into the output
+ * parameter `*n` and returns `TRUE`. Otherwise, it returns `FALSE`.
+ *
+ * @param s The current code generation scope (used to access the literal pool for `OP_LOADL`).
+ * @param data Pointer to an `mrb_insn_data` structure describing the instruction.
+ * @param n Output parameter: pointer to an `mrb_int` where the extracted integer
+ * value will be stored if successful.
+ * @return `TRUE` if an integer value was successfully extracted, `FALSE` otherwise.
+ */
static mrb_bool
get_int_operand(codegen_scope *s, struct mrb_insn_data *data, mrb_int *n)
{
@@ -799,33 +1240,107 @@ get_int_operand(codegen_scope *s, struct mrb_insn_data *data, mrb_int *n)
static int new_lit_str2(codegen_scope *s, const char *str1, mrb_int len1, const char *str2, mrb_int len2);
static int find_pool_str(codegen_scope *s, const char *str1, mrb_int len1, const char *str2, mrb_int len2);
+static void gen_string(codegen_scope *s, node *list, int val);
+/*
+ * Reallocates or allocates memory for a string literal in the IREP's literal pool.
+ *
+ * This function is used when a string literal needs to be resized, typically
+ * during string concatenation optimizations (`merge_op_string`).
+ *
+ * - If the original pool entry `p` pointed to a shared string (e.g., a string
+ * from read-only data, `IREP_TT_SSTR`), new memory is allocated for the resized string.
+ * - If `p` was already a dynamically allocated string (`IREP_TT_STR`), its buffer
+ * is reallocated to the new `len`.
+ *
+ * After allocation/reallocation, the pool entry `p` is updated:
+ * - Its type `tt` is set to `IREP_TT_STR` (or kept as `IREP_TT_STR`).
+ * - The length in `tt` is updated to the new `len`.
+ * - The string is null-terminated.
+ * - `p->u.str` points to the new or reallocated buffer.
+ *
+ * @param s The current code generation scope.
+ * @param p Pointer to the `mrb_irep_pool` entry for the string literal.
+ * @param len The new length of the string (excluding the null terminator).
+ */
static void
realloc_pool_str(codegen_scope *s, mrb_irep_pool *p, mrb_int len)
{
char *str;
- if ((p->tt & 3) == IREP_TT_SSTR) {
- str = (char*)codegen_realloc(s, NULL, len+1);
+ mrb_int olen = p->tt >> 2; /* original length */
+ if ((p->tt & 3) == IREP_TT_SSTR) { /* Check if it's a shared/static string */
+ const char *old = p->u.str;
+ str = (char*)mrbc_malloc(len+1); /* Allocate new memory if it was shared */
+ memcpy(str, old, olen); /* Copy original content */
}
- else {
+ else { /* It's already a heap-allocated string */
str = (char*)p->u.str;
- str = (char*)codegen_realloc(s, str, len+1);
+ str = (char*)mrbc_realloc(str, len+1);
}
- p->tt = len<<2 | IREP_TT_STR;
+ p->tt = (uint32_t)(len<<2 | IREP_TT_STR);
str[len] = '\0';
p->u.str = (const char*)str;
}
+/*
+ * Frees the memory associated with a string literal in the IREP's literal pool,
+ * if it's not a shared (static) string.
+ *
+ * This function is typically called when a string literal pool entry is being
+ * effectively removed or replaced due to optimizations like string merging.
+ *
+ * - It checks if the pool entry `p`'s type `tt` indicates it's a dynamically
+ * allocated string (not `IREP_TT_SSTR`).
+ * - If so, it frees the memory pointed to by `p->u.str`.
+ * - It then sets `p->u.str` to `NULL` and decrements the total count of literals
+ * in the pool (`s->irep->plen`). Note: This decrement might be problematic if
+ * pool entries are not compacted, as it could lead to an incorrect `plen`.
+ *
+ * @param s The current code generation scope.
+ * @param p Pointer to the `mrb_irep_pool` entry of the string to be freed.
+ */
static void
free_pool_str(codegen_scope *s, mrb_irep_pool *p)
{
- if ((p->tt & 3) != IREP_TT_SSTR) {
- codegen_realloc(s, (char*)p->u.str, 0);
+ if ((p->tt & 3) != IREP_TT_SSTR) { /* Only free if not a shared/static string */
+ mrbc_free((char*)p->u.str);
}
p->u.str = NULL;
- s->irep->plen--;
+ s->irep->plen--; /* Decrements the count of pool entries. */
}
+/*
+ * Performs a peephole optimization for string concatenation.
+ *
+ * This function is called when an `OP_ADD` (string concatenation) instruction
+ * is encountered. It checks if the two operands to `OP_ADD` were themselves
+ * loaded by `OP_STRING` instructions (i.e., string literals from the pool
+ * at indices `b1` and `b2`).
+ *
+ * If this pattern is found, `merge_op_string` attempts to:
+ * 1. Determine if the literal pool entries `b1` and `b2` are used by any other
+ * `OP_STRING` instructions prior to the instruction at `pc` (the start of the
+ * first `OP_STRING` in the sequence).
+ * 2. Based on this usage (`used` flags), it decides on a strategy to merge
+ * the string content of `b1` and `b2`:
+ * - If neither `b1` nor `b2` is otherwise referenced, or only `b2` is, it reuses
+ * and resizes pool entry `b1` to hold the concatenated string. If `b2` was
+ * the last entry in the pool and not shared, `b2` is freed.
+ * - If only `b1` is referenced, it reuses and resizes pool entry `b2`.
+ * - If both `b1` and `b2` are referenced by other instructions, it creates a
+ * new literal pool entry for the concatenated string.
+ * 3. If an existing pool entry already matches the concatenated string, that entry is used.
+ * 4. Finally, it rewinds the program counter to `pc` (the location of the original
+ * first `OP_STRING`) and generates a single `OP_STRING` instruction to load the
+ * merged/reused literal into the destination register `dst`.
+ *
+ * @param s The current code generation scope.
+ * @param dst The destination register for the result of the concatenation.
+ * @param b1 The pool index of the first string literal.
+ * @param b2 The pool index of the second string literal.
+ * @param pc The program counter of the instruction that loaded the first string literal (`b1`).
+ * This is where the new merged `OP_STRING` will be generated.
+ */
static void
merge_op_string(codegen_scope *s, uint16_t dst, uint16_t b1, uint16_t b2, const mrb_code *pc)
{
@@ -860,7 +1375,7 @@ merge_op_string(codegen_scope *s, uint16_t dst, uint16_t b1, uint16_t b2, const
mrb_irep_pool *p2 = &s->pool[b2];
mrb_int len1 = p1->tt>>2;
mrb_int len2 = p2->tt>>2;
- int off = find_pool_str(s, p1->u.str, len1, p2->u.str, len2);;
+ int off = find_pool_str(s, p1->u.str, len1, p2->u.str, len2);
if (off < 0) {
switch (used) {
@@ -891,6 +1406,31 @@ merge_op_string(codegen_scope *s, uint16_t dst, uint16_t b1, uint16_t b2, const
genop_2(s, OP_STRING, dst, off);
}
+/*
+ * Generates code for addition (`OP_ADD`) or subtraction (`OP_SUB`)
+ * operations, storing the result in register `dst`.
+ *
+ * This function includes several peephole optimizations:
+ * 1. String Concatenation: If `op` is `OP_ADD` and the two preceding instructions
+ * were `OP_STRING` (loading string literals), it calls `merge_op_string`
+ * to attempt compile-time concatenation of these literals.
+ * 2. Immediate Operations: If the last instruction loaded an integer literal (`n`)
+ * and the instruction before that loaded another integer (`n0`), but `n0` is not
+ * suitable for further folding (e.g., it's at a label, or the instruction
+ * before it isn't an integer load), it attempts to convert the operation to
+ * `OP_ADDI` or `OP_SUBI` if `n` fits within an 8-bit signed integer.
+ * 3. Constant Folding: If both the last two instructions loaded integer literals
+ * (`n0` and `n`), it performs the addition or subtraction at compile time.
+ * The program counter is rewound to the location of the first literal load,
+ * and code is generated to load the folded result directly using `gen_int`.
+ *
+ * If no optimizations are applicable, it generates the standard `OP_ADD` or `OP_SUB`
+ * instruction.
+ *
+ * @param s The current code generation scope.
+ * @param op The operation code, either `OP_ADD` or `OP_SUB`.
+ * @param dst The destination register index for the result.
+ */
static void
gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst)
{
@@ -943,6 +1483,27 @@ gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst)
}
}
+/*
+ * Generates code for multiplication (`OP_MUL`) or division (`OP_DIV`)
+ * operations, storing the result in register `dst`.
+ *
+ * Peephole Optimization (Constant Folding):
+ * - If peephole optimization is enabled and the two immediately preceding
+ * instructions loaded integer literals (into registers that are operands
+ * for this multiplication/division), this function performs the operation
+ * at compile time.
+ * - The program counter is rewound to the location of the first literal load,
+ * and code is generated to load the folded result directly using `gen_int`.
+ * - For division, if the divisor is zero or if it's `MRB_INT_MIN / -1` (which
+ * would overflow), the optimization is skipped.
+ *
+ * If no optimization is applicable, it generates the standard `OP_MUL` or `OP_DIV`
+ * instruction.
+ *
+ * @param s The current code generation scope.
+ * @param op The operation code, either `OP_MUL` or `OP_DIV`.
+ * @param dst The destination register index for the result.
+ */
static void
gen_muldiv(codegen_scope *s, uint8_t op, uint16_t dst)
{
@@ -977,11 +1538,47 @@ gen_muldiv(codegen_scope *s, uint8_t op, uint16_t dst)
mrb_bool mrb_num_shift(mrb_state *mrb, mrb_int val, mrb_int width, mrb_int *num);
+/*
+ * Generates code for various binary operations, identified by `sym_op`,
+ * storing the result in register `dst`.
+ *
+ * This function handles specific binary operations and includes peephole
+ * optimizations for constant folding when operands are integer literals.
+ *
+ * Operations Handled & Optimizations:
+ * - `aref` (`[]`): Generates `OP_GETIDX`.
+ * - Bitwise shifts (`<<`, `>>`): If both operands are integer literals,
+ * performs the shift at compile time using `mrb_num_shift` and loads the result.
+ * - Modulo (`%`): If both operands are integer literals, performs modulo
+ * at compile time and loads the result. Handles `MRB_INT_MIN % -1`.
+ * - Bitwise AND (`&`), OR (`|`), XOR (`^`): If both operands are integer
+ * literals, performs the operation at compile time and loads the result.
+ *
+ * If an optimization is applied (e.g., constant folding), the program counter
+ * is rewound, and `gen_int` is used to load the computed result.
+ *
+ * @param s The current code generation scope.
+ * @param op The `mrb_sym` representing the binary operator (e.g., `MRB_OPSYM_LSHIFT`).
+ * @param dst The destination register index for the result.
+ * @return `TRUE` if a specific optimization was applied (like `OP_GETIDX` or constant folding),
+ * `FALSE` otherwise. A `FALSE` return typically indicates that a generic
+ * `OP_SEND` instruction should be generated for the operation.
+ */
static mrb_bool
gen_binop(codegen_scope *s, mrb_sym op, uint16_t dst)
{
if (no_peephole(s)) return FALSE;
- else if (op == MRB_OPSYM_2(s->mrb, aref)) {
+ else if (op == MRB_OPSYM(aref)) {
+ /* GETIDX0 fusion: MOVE dst arr; LOADI_0 dst+1 -> GETIDX0 dst arr */
+ struct mrb_insn_data data = mrb_last_insn(s);
+ if (data.insn == OP_LOADI_0 && data.a == (uint32_t)dst+1 && addr_pc(s, data.addr) != s->lastlabel) {
+ struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr));
+ if (data0.insn == OP_MOVE && data0.a == dst && data0.b != dst) {
+ s->pc = addr_pc(s, data0.addr);
+ genop_2(s, OP_GETIDX0, dst, data0.b);
+ return TRUE;
+ }
+ }
genop_1(s, OP_GETIDX, dst);
return TRUE;
}
@@ -996,14 +1593,14 @@ gen_binop(codegen_scope *s, mrb_sym op, uint16_t dst)
if (!get_int_operand(s, &data0, &n0)) {
return FALSE;
}
- if (op == MRB_OPSYM_2(s->mrb, lshift)) {
+ if (op == MRB_OPSYM(lshift)) {
if (!mrb_num_shift(s->mrb, n0, n, &n)) return FALSE;
}
- else if (op == MRB_OPSYM_2(s->mrb, rshift)) {
+ else if (op == MRB_OPSYM(rshift)) {
if (n == MRB_INT_MIN) return FALSE;
if (!mrb_num_shift(s->mrb, n0, -n, &n)) return FALSE;
}
- else if (op == MRB_OPSYM_2(s->mrb, mod) && n != 0) {
+ else if (op == MRB_OPSYM(mod) && n != 0) {
if (n0 == MRB_INT_MIN && n == -1) {
n = 0;
}
@@ -1015,13 +1612,13 @@ gen_binop(codegen_scope *s, mrb_sym op, uint16_t dst)
n = n1;
}
}
- else if (op == MRB_OPSYM_2(s->mrb, and)) {
+ else if (op == MRB_OPSYM(and)) {
n = n0 & n;
}
- else if (op == MRB_OPSYM_2(s->mrb, or)) {
+ else if (op == MRB_OPSYM(or)) {
n = n0 | n;
}
- else if (op == MRB_OPSYM_2(s->mrb, xor)) {
+ else if (op == MRB_OPSYM(xor)) {
n = n0 ^ n;
}
else {
@@ -1033,6 +1630,32 @@ gen_binop(codegen_scope *s, mrb_sym op, uint16_t dst)
}
}
+/*
+ * Resolves the target address of a previously generated jump instruction.
+ *
+ * Jump instructions are often generated with placeholder offsets (e.g., 0 or a
+ * link to another jump) when their final target is not yet known. This function
+ * patches such a jump.
+ *
+ * `pos0` is the program counter (address) of the 2-byte field within a jump
+ * instruction that holds its offset (or a link in a jump chain).
+ *
+ * The function calculates the correct relative offset from the instruction
+ * *after* the jump's offset field (`pos0 + 2`) to the current program
+ * counter (`s->pc`), which is the actual target of the jump. This calculated
+ * offset is then written back into the bytecode at `pos0`.
+ *
+ * If the original value at `pos0` was not 0 (i.e., it was part of a jump chain,
+ * pointing to the next jump to patch), this original value (which is an offset
+ * relative to `pos0 + 2`) is returned so that `dispatch_linked` can continue
+ * patching the chain. If the original value was 0, it signifies the end of a chain,
+ * and 0 is returned.
+ *
+ * @param s The current code generation scope.
+ * @param pos0 The address of the 2-byte offset field within a jump instruction.
+ * @return The next position in a jump chain to dispatch (calculated from the
+ * original offset stored at `pos0`), or 0 if it's the end of a chain.
+ */
static uint32_t
dispatch(codegen_scope *s, uint32_t pos0)
{
@@ -1054,6 +1677,25 @@ dispatch(codegen_scope *s, uint32_t pos0)
return pos1+newpos;
}
+/*
+ * Patches a chain of linked jump instructions to all point to the current
+ * program counter (`s->pc`).
+ *
+ * Jump instructions whose targets are not yet known can be linked together.
+ * Each jump's offset field initially stores the relative offset to the next
+ * jump in the chain (or 0 if it's the last one). `pos` is the address of the
+ * first jump's offset field in such a chain.
+ *
+ * This function iterates through the chain:
+ * - It calls `dispatch(s, pos)` to patch the jump at `pos` to target the current `s->pc`.
+ * - `dispatch` returns the address of the next jump in the chain (or 0 if the end).
+ * - The process repeats until the end of the chain is reached.
+ *
+ * If `pos` is `JMPLINK_START`, it means there's no chain to dispatch, so it returns early.
+ *
+ * @param s The current code generation scope.
+ * @param pos The address of the offset field of the first jump instruction in a linked chain.
+ */
static void
dispatch_linked(codegen_scope *s, uint32_t pos)
{
@@ -1064,6 +1706,7 @@ dispatch_linked(codegen_scope *s, uint32_t pos)
}
}
+/* Updates the nregs (number of registers used) if the current stack pointer (sp) exceeds it. */
#define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0)
static void
push_n_(codegen_scope *s, int n)
@@ -1084,23 +1727,94 @@ pop_n_(codegen_scope *s, int n)
s->sp-=n;
}
+/* Increments the stack pointer (sp) by 1 and updates nregs. */
#define push() push_n_(s,1)
+/* Increments the stack pointer (sp) by n and updates nregs. */
#define push_n(n) push_n_(s,n)
+/* Decrements the stack pointer (sp) by 1. */
#define pop() pop_n_(s,1)
+/* Decrements the stack pointer (sp) by n. */
#define pop_n(n) pop_n_(s,n)
+/* Returns the current stack pointer (sp) value. */
#define cursp() (s->sp)
+/*
+ * Extends the literal pool (`s->pool`) of the current IREP (`s->irep`) if necessary.
+ *
+ * If the number of literals currently in the pool (`s->irep->plen`) has reached
+ * the pool's capacity (`s->pcapa`), this function doubles the capacity by
+ * reallocating the `s->pool` array.
+ * After ensuring there's space, it increments `s->irep->plen` and returns a pointer
+ * to the newly available slot in the literal pool.
+ *
+ * @param s The current code generation scope.
+ * @return A pointer to the next available (or newly allocated) `mrb_irep_pool` entry.
+ */
static mrb_irep_pool*
lit_pool_extend(codegen_scope *s)
{
if (s->irep->plen == s->pcapa) {
s->pcapa *= 2;
- s->pool = (mrb_irep_pool*)codegen_realloc(s, s->pool, sizeof(mrb_irep_pool)*s->pcapa);
+ s->pool = (mrb_irep_pool*)mrbc_realloc(s->pool, sizeof(mrb_irep_pool)*s->pcapa);
}
return &s->pool[s->irep->plen++];
}
+/* Helper functions for simple load operations that follow the pattern:
+ * if (!val) return; <prepare>; genop_X(...); push(); */
+static void
+gen_load_op1(codegen_scope *s, mrb_code op, int val)
+{
+ if (!val) return;
+ genop_1(s, op, cursp());
+ push();
+}
+
+static void
+gen_load_op2(codegen_scope *s, mrb_code op, uint16_t arg, int val)
+{
+ if (!val) return;
+ genop_2(s, op, cursp(), arg);
+ push();
+}
+
+/* Helper function for conditional nil loading - loads nil only if val is needed */
+static void
+gen_load_nil(codegen_scope *s, int val)
+{
+ if (!val) return;
+ genop_1(s, OP_LOADNIL, cursp());
+ push();
+}
+
+/* Helper function for loading literal and pushing */
+static void
+gen_load_lit(codegen_scope *s, int off)
+{
+ genop_2(s, OP_LOADL, cursp(), off);
+ push();
+}
+
+/*
+ * Adds a big integer literal (BigInt) to the IREP's literal pool.
+ * The BigInt is provided as a string `p` in the given `base`.
+ *
+ * - It first searches the existing literal pool to see if an identical BigInt
+ * (same string representation and base) already exists. If so, its index is returned.
+ * - If not found, a new entry is created in the pool:
+ * - The pool is extended if necessary using `lit_pool_extend`.
+ * - The new pool entry's type `tt` is set to `IREP_TT_BIGINT`.
+ * - Memory is allocated to store the BigInt's string representation, its length (1 byte),
+ * and its base (1 byte). The string `p` is copied into this buffer.
+ * - `pv->u.str` points to this allocated buffer.
+ * - If the length of the string `p` exceeds 255, a "integer too big" error is raised.
+ *
+ * @param s The current code generation scope.
+ * @param p A string representing the big integer.
+ * @param base The base of the string representation (e.g., 10 for decimal).
+ * @return The index of the BigInt literal in the pool.
+ */
static int
new_litbint(codegen_scope *s, const char *p, int base)
{
@@ -1125,7 +1839,7 @@ new_litbint(codegen_scope *s, const char *p, int base)
char *buf;
pv->tt = IREP_TT_BIGINT;
- buf = (char*)codegen_realloc(s, NULL, plen+3);
+ buf = (char*)mrbc_malloc(plen+3);
buf[0] = (char)plen;
buf[1] = base;
memcpy(buf+2, p, plen);
@@ -1135,6 +1849,23 @@ new_litbint(codegen_scope *s, const char *p, int base)
return i;
}
+/*
+ * Searches the IREP's literal pool for an existing string that is identical
+ * to the concatenation of `str1` (of length `len1`) and `str2` (of length `len2`).
+ *
+ * It iterates through the existing literal pool entries:
+ * - Skips entries that are not strings or are marked with `IREP_TT_NFLAG`.
+ * - Compares the total length (`len1 + len2`) with the length of the pool string.
+ * - If lengths match, it performs a `memcmp` to check if the content is identical
+ * to the concatenation of `str1` and `str2`.
+ *
+ * @param s The current code generation scope.
+ * @param str1 Pointer to the first part of the string to find.
+ * @param len1 Length of `str1`.
+ * @param str2 Pointer to the second part of the string to find (can be NULL if `len2` is 0).
+ * @param len2 Length of `str2`.
+ * @return The index of the matching string literal in the pool if found, otherwise -1.
+ */
static int
find_pool_str(codegen_scope *s, const char *str1, mrb_int len1, const char *str2, mrb_int len2)
{
@@ -1154,6 +1885,32 @@ find_pool_str(codegen_scope *s, const char *str1, mrb_int len1, const char *str2
return -1;
}
+/*
+ * Adds a string literal, potentially formed by concatenating `str1` and `str2`,
+ * to the IREP's literal pool.
+ *
+ * - It first calls `find_pool_str` to check if an identical concatenated string
+ * already exists in the pool. If so, its index is returned.
+ * - If not found:
+ * - A new slot in the literal pool is obtained using `lit_pool_extend`.
+ * - If `str1` points to read-only data (`mrb_ro_data_p(str1)`) and `str2` is NULL
+ * (meaning `str1` is the complete string and it's from a static source),
+ * the pool entry is marked as `IREP_TT_SSTR` (shared string) and `pool->u.str`
+ * points directly to `str1`.
+ * - Otherwise (if the string needs to be dynamically created or is not from
+ * read-only data), memory is allocated for the combined length of `str1` and
+ * `str2` plus a null terminator. `str1` and `str2` (if present) are copied
+ * into this new buffer. The pool entry is marked as `IREP_TT_STR`, and
+ * `pool->u.str` points to this newly allocated buffer.
+ * - The index of the new or found literal is returned.
+ *
+ * @param s The current code generation scope.
+ * @param str1 Pointer to the first part of the string.
+ * @param len1 Length of `str1`.
+ * @param str2 Pointer to the second part of the string (can be NULL if `len2` is 0).
+ * @param len2 Length of `str2`.
+ * @return The index of the string literal in the pool.
+ */
static int
new_lit_str2(codegen_scope *s, const char *str1, mrb_int len1, const char *str2, mrb_int len2)
{
@@ -1172,7 +1929,7 @@ new_lit_str2(codegen_scope *s, const char *str1, mrb_int len1, const char *str2,
else {
char *p;
pool->tt = (uint32_t)(len<<2) | IREP_TT_STR;
- p = (char*)codegen_realloc(s, NULL, len+1);
+ p = (char*)mrbc_malloc(len+1);
memcpy(p, str1, len1);
if (str2) memcpy(p+len1, str2, len2);
p[len] = '\0';
@@ -1182,18 +1939,50 @@ new_lit_str2(codegen_scope *s, const char *str1, mrb_int len1, const char *str2,
return i;
}
+/*
+ * Adds a string literal (from `str` with length `len`) to the IREP's literal pool.
+ * This is a wrapper around `new_lit_str2`, passing NULL for `str2` and 0 for `len2`.
+ *
+ * @param s The current code generation scope.
+ * @param str Pointer to the string.
+ * @param len Length of the string.
+ * @return The index of the string literal in the pool.
+ */
static int
new_lit_str(codegen_scope *s, const char *str, mrb_int len)
{
return new_lit_str2(s, str, len, NULL, 0);
}
+/*
+ * Adds a C-string literal (null-terminated string `str`) to the IREP's literal pool.
+ * This is a wrapper around `new_lit_str`, calculating the length of `str` using `strlen`.
+ *
+ * @param s The current code generation scope.
+ * @param str Pointer to the null-terminated C-string.
+ * @return The index of the string literal in the pool.
+ */
static int
new_lit_cstr(codegen_scope *s, const char *str)
{
return new_lit_str(s, str, (mrb_int)strlen(str));
}
+/*
+ * Adds an integer literal `num` to the IREP's literal pool.
+ *
+ * - It first searches the existing literal pool to see if an identical integer
+ * value already exists. If so, its index is returned.
+ * - If not found, a new entry is created:
+ * - The pool is extended if necessary using `lit_pool_extend`.
+ * - The new pool entry's type `tt` is set to `IREP_TT_INT32` or `IREP_TT_INT64`
+ * depending on whether `MRB_INT64` is defined.
+ * - The integer `num` is stored in `pool->u.i32` or `pool->u.i64`.
+ *
+ * @param s The current code generation scope.
+ * @param num The `mrb_int` value to add to the pool.
+ * @return The index of the integer literal in the pool.
+ */
static int
new_lit_int(codegen_scope *s, mrb_int num)
{
@@ -1227,6 +2016,22 @@ new_lit_int(codegen_scope *s, mrb_int num)
}
#ifndef MRB_NO_FLOAT
+/*
+ * Adds a float literal `num` to the IREP's literal pool.
+ * This function is only compiled if `MRB_NO_FLOAT` is not defined.
+ *
+ * - It first searches the existing literal pool to see if an identical float
+ * value (considering both value and sign bit) already exists. If so, its
+ * index is returned.
+ * - If not found, a new entry is created:
+ * - The pool is extended if necessary using `lit_pool_extend`.
+ * - The new pool entry's type `tt` is set to `IREP_TT_FLOAT`.
+ * - The float `num` is stored in `pool->u.f`.
+ *
+ * @param s The current code generation scope.
+ * @param num The `mrb_float` value to add to the pool.
+ * @return The index of the float literal in the pool.
+ */
static int
new_lit_float(codegen_scope *s, mrb_float num)
{
@@ -1250,8 +2055,25 @@ new_lit_float(codegen_scope *s, mrb_float num)
}
#endif
+/*
+ * Adds a symbol `sym` to the IREP's symbol list (`s->syms`).
+ *
+ * - It first iterates through the existing symbols in `s->syms` (up to `s->irep->slen`)
+ * to check if the symbol `sym` already exists. If found, its index is returned.
+ * - If the symbol is not found:
+ * - It checks if the current symbol list capacity (`s->scapa`) is sufficient.
+ * If not, `s->scapa` is doubled, and `s->syms` is reallocated.
+ * If the new capacity would exceed 0xFFFF, a "too many symbols" error is raised.
+ * - The symbol `sym` is added to `s->syms` at the current end of the list (`s->irep->slen`).
+ * - `s->irep->slen` is incremented.
+ * - The index of the (newly added or existing) symbol is returned.
+ *
+ * @param s The current code generation scope.
+ * @param sym The `mrb_sym` to add to the symbol list.
+ * @return The index of the symbol in the IREP's symbol list.
+ */
static int
-new_sym(codegen_scope *s, mrb_sym sym)
+sym_idx(codegen_scope *s, mrb_sym sym)
{
int i, len;
@@ -1266,16 +2088,40 @@ new_sym(codegen_scope *s, mrb_sym sym)
if (s->scapa > 0xffff) {
codegen_error(s, "too many symbols");
}
- s->syms = (mrb_sym*)codegen_realloc(s, s->syms, sizeof(mrb_sym)*s->scapa);
+ s->syms = (mrb_sym*)mrbc_realloc(s->syms, sizeof(mrb_sym)*s->scapa);
}
s->syms[s->irep->slen] = sym;
return s->irep->slen++;
}
+/*
+ * Generates an instruction to set a variable, where the variable is identified by a symbol.
+ * This is a generic helper for opcodes like `OP_SETGV`, `OP_SETIV`, `OP_SETCV`, `OP_SETCONST`.
+ *
+ * - It first ensures the symbol `sym` is in the IREP's symbol list by calling `sym_idx`,
+ * obtaining its index `idx`.
+ * - Peephole Optimization: If `val` is `NOVAL` (false) and peephole optimization is enabled,
+ * it checks if the immediately preceding instruction was an `OP_MOVE` into the `dst`
+ * register. If so, it means the value intended for the variable assignment was moved
+ * into `dst`. In this case, it rewinds the program counter and uses the original source
+ * register of that `OP_MOVE` as the source for the set operation, effectively using
+ * the value before it was moved to `dst`.
+ * - Finally, it generates the specified opcode `op` with operands `dst` (the source
+ * register for the value, possibly modified by peephole optimization) and `idx`
+ * (the symbol index) using `genop_2`.
+ *
+ * @param s The current code generation scope.
+ * @param op The specific set variable opcode (e.g., `OP_SETGV`, `OP_SETIV`).
+ * @param dst The register index holding the value to be assigned to the variable.
+ * @param sym The `mrb_sym` (symbol) identifying the variable.
+ * @param val A flag indicating context (often whether the value in `dst` is from an
+ * expression that should be preserved if the set operation is part of a larger one).
+ * If `NOVAL`, it enables the peephole optimization.
+ */
static void
gen_setxv(codegen_scope *s, uint8_t op, uint16_t dst, mrb_sym sym, int val)
{
- int idx = new_sym(s, sym);
+ int idx = sym_idx(s, sym);
if (!val && !no_peephole(s)) {
struct mrb_insn_data data = mrb_last_insn(s);
if (data.insn == OP_MOVE && data.a == dst) {
@@ -1286,6 +2132,29 @@ gen_setxv(codegen_scope *s, uint8_t op, uint16_t dst, mrb_sym sym, int val)
genop_2(s, op, dst, idx);
}
+/*
+ * Generates the most compact instruction(s) to load an integer literal `i`
+ * into the destination register `dst`.
+ *
+ * It employs a series of checks to use specialized, shorter opcodes for common integer values:
+ * - `OP_LOADI__1` for -1.
+ * - `OP_LOADINEG` for negative integers between -255 and -2 (operand is positive magnitude).
+ * - `OP_LOADI16` for negative integers fitting in a signed 16-bit integer (INT16_MIN to -256).
+ * - `OP_LOADI32` for negative integers fitting in a signed 32-bit integer (INT32_MIN to not fitting in 16-bit).
+ * - `OP_LOADI_0` through `OP_LOADI_7` for integers 0 through 7.
+ * - `OP_LOADI8` for positive integers between 8 and 255.
+ * - `OP_LOADI16` for positive integers fitting in a signed 16-bit integer (256 to INT16_MAX).
+ * - `OP_LOADI32` for positive integers fitting in a signed 32-bit integer (not fitting in 16-bit to INT32_MAX).
+ *
+ * If the integer `i` does not fit any of these specialized opcodes (i.e., it's too large
+ * or too small for `OP_LOADI32`), it falls back to `OP_LOADL`. This involves adding
+ * the integer to the IREP's literal pool using `new_lit_int` and then generating
+ * `OP_LOADL` with the resulting pool index.
+ *
+ * @param s The current code generation scope.
+ * @param dst The destination register index where the integer will be loaded.
+ * @param i The `mrb_int` value to load.
+ */
static void
gen_int(codegen_scope *s, uint16_t dst, mrb_int i)
{
@@ -1306,6 +2175,36 @@ gen_int(codegen_scope *s, uint16_t dst, mrb_int i)
}
}
+/*
+ * Generates code for a unary operation specified by `sym`, operating on the
+ * value in register `dst`, and storing the result back into `dst`.
+ *
+ * Supported unary operations:
+ * - Unary plus (`+`): This is a no-op in terms of value change, but the function
+ * still processes it.
+ * - Unary minus (`-`): Negates the integer value.
+ * - Bitwise NOT (`~`): Performs a bitwise complement on the integer value.
+ *
+ * Peephole Optimization (Constant Folding):
+ * - If peephole optimization is enabled and the immediately preceding instruction
+ * loaded an integer literal into register `dst` (which is also the operand
+ * register for this unary operation), this function performs the unary operation
+ * at compile time.
+ * - The program counter is rewound to the location of the literal load, and code
+ * is generated to load the folded result directly using `gen_int`.
+ * - For unary minus, if the original integer is `MRB_INT_MIN`, constant folding
+ * is skipped to avoid overflow.
+ *
+ * If the operation is not one of the recognized unary ops or if constant folding
+ * is not applicable, the function returns `FALSE`.
+ *
+ * @param s The current code generation scope.
+ * @param sym The `mrb_sym` representing the unary operator (e.g., `MRB_OPSYM_PLUS`, `MRB_OPSYM_MINUS`).
+ * @param dst The register index which holds the operand and will store the result.
+ * @return `TRUE` if a constant folding optimization was successfully applied,
+ * `FALSE` otherwise (e.g., if the operation is not supported for folding,
+ * or if the preceding instruction was not a suitable integer load).
+ */
static mrb_bool
gen_uniop(codegen_scope *s, mrb_sym sym, uint16_t dst)
{
@@ -1314,14 +2213,14 @@ gen_uniop(codegen_scope *s, mrb_sym sym, uint16_t dst)
mrb_int n;
if (!get_int_operand(s, &data, &n)) return FALSE;
- if (sym == MRB_OPSYM_2(s->mrb, plus)) {
+ if (sym == MRB_OPSYM(plus)) {
/* unary plus does nothing */
}
- else if (sym == MRB_OPSYM_2(s->mrb, minus)) {
+ else if (sym == MRB_OPSYM(minus)) {
if (n == MRB_INT_MIN) return FALSE;
n = -n;
}
- else if (sym == MRB_OPSYM_2(s->mrb, neg)) {
+ else if (sym == MRB_OPSYM(neg)) {
n = ~n;
}
else {
@@ -1332,11 +2231,23 @@ gen_uniop(codegen_scope *s, mrb_sym sym, uint16_t dst)
return TRUE;
}
+/*
+ * Calculates and returns the number of elements in a linked list of AST nodes.
+ * The list is traversed via the `cdr` field of each `node`.
+ *
+ * @param tree Pointer to the head of the AST node list.
+ * @return The number of nodes in the list.
+ */
static int
node_len(node *tree)
{
int n = 0;
+ /* Validate pointer before using it */
+ if (!tree || ((uintptr_t)tree < 0x1000)) {
+ return 0;
+ }
+
while (tree) {
n++;
tree = tree->cdr;
@@ -1344,12 +2255,26 @@ node_len(node *tree)
return n;
}
-#define nint(x) ((int)(intptr_t)(x))
-#define nchar(x) ((char)(intptr_t)(x))
-#define nsym(x) ((mrb_sym)(intptr_t)(x))
+/* Casts a void* (typically from an AST node part) to an int. */
+#define node_to_sym(x) ((mrb_sym)(intptr_t)(x))
+#define node_to_int(x) ((int)(intptr_t)(x))
+/* Casts a void* (typically from an AST node part) to a char. */
+#define node_to_char(x) ((char)(intptr_t)(x))
+/* Casts a void* (typically from an AST node part) to an mrb_sym. */
-#define lv_name(lv) nsym((lv)->car)
+/* Extracts the symbol (name) of a local variable from its AST node representation. */
+#define lv_name(lv) node_to_sym((lv)->car)
+/*
+ * Searches for a local variable `id` within the current scope's local variable list (`s->lv`).
+ * The local variable list `s->lv` is a linked list of AST nodes, where each node's
+ * `car` holds the symbol of the local variable.
+ *
+ * @param s The current code generation scope.
+ * @param id The `mrb_sym` (symbol) of the local variable to search for.
+ * @return The 1-based index of the local variable in the current scope if found;
+ * otherwise, returns 0.
+ */
static int
lv_idx(codegen_scope *s, mrb_sym id)
{
@@ -1401,13 +2326,13 @@ search_upvar(codegen_scope *s, mrb_sym id, int *idx)
lv++;
}
- if (id == MRB_OPSYM_2(s->mrb, and)) {
+ if (id == MRB_OPSYM(and)) {
codegen_error(s, "No anonymous block parameter");
}
- else if (id == MRB_OPSYM_2(s->mrb, mul)) {
+ else if (id == MRB_OPSYM(mul)) {
codegen_error(s, "No anonymous rest parameter");
}
- else if (id == MRB_OPSYM_2(s->mrb, pow)) {
+ else if (id == MRB_OPSYM(pow)) {
codegen_error(s, "No anonymous keyword rest parameter");
}
else {
@@ -1416,162 +2341,136 @@ search_upvar(codegen_scope *s, mrb_sym id, int *idx)
return -1; /* not reached */
}
-static void
-for_body(codegen_scope *s, node *tree)
-{
- codegen_scope *prev = s;
- int idx;
- struct loopinfo *lp;
- node *n2;
-
- /* generate receiver */
- codegen(s, tree->cdr->car, VAL);
- /* generate loop-block */
- s = scope_new(s->mrb, s, NULL);
-
- push(); /* push for a block parameter */
-
- /* generate loop variable */
- n2 = tree->car;
- genop_W(s, OP_ENTER, 0x40000);
- if (n2->car && !n2->car->cdr && !n2->cdr) {
- gen_assignment(s, n2->car->car, NULL, 1, NOVAL);
- }
- else {
- gen_massignment(s, n2, 1, VAL);
- }
- /* construct loop */
- lp = loop_push(s, LOOP_FOR);
- lp->pc1 = new_label(s);
- genop_0(s, OP_NOP); /* for redo */
-
- /* loop body */
- codegen(s, tree->cdr->cdr->car, VAL);
- pop();
- gen_return(s, OP_RETURN, cursp());
- loop_pop(s, NOVAL);
- scope_finish(s);
- s = prev;
- genop_2(s, OP_BLOCK, cursp(), s->irep->rlen-1);
- push();pop(); /* space for a block */
- pop();
- idx = new_sym(s, MRB_SYM_2(s->mrb, each));
- genop_3(s, OP_SENDB, cursp(), idx, 0);
-}
-
+/*
+ * Generates the bytecode for the body of a lambda or a block.
+ * This function is responsible for creating a new scope, handling arguments
+ * (including optional, rest, keyword, and block arguments), generating code
+ * for the body's expressions, and finalizing the resulting `mrb_irep`.
+ *
+ * @param s The parent code generation scope.
+ * @param tree The AST node representing the lambda or block.
+ * `tree->car` contains the argument list AST.
+ * `tree->cdr->car` is the body of the lambda/block.
+ * @param blk A flag indicating if this is a block (`TRUE`) or a lambda (`FALSE`).
+ * This affects `s->mscope` and loop setup.
+ * @return The index of the newly created `mrb_irep` in the parent scope's `reps` array.
+ */
static int
-lambda_body(codegen_scope *s, node *tree, int blk)
+lambda_body(codegen_scope *s, node *locals, struct mrb_ast_args *args, node *body, int blk)
{
codegen_scope *parent = s;
- s = scope_new(s->mrb, s, tree->car);
+ /* Create a new scope for the lambda/block body. */
+ s = scope_new(s->mrb, s, locals);
+ /* `mscope` is false for blocks, true for lambdas/methods. */
s->mscope = !blk;
+ /* If it's a block, push a LOOP_BLOCK structure for break/next/return handling. */
if (blk) {
struct loopinfo *lp = loop_push(s, LOOP_BLOCK);
- lp->pc0 = new_label(s);
+ lp->pc0 = new_label(s); /* Mark entry point for potential retry/redo. */
}
- tree = tree->cdr;
- if (tree->car == NULL) {
- genop_W(s, OP_ENTER, 0);
+
+ /* Argument processing */
+ if (args == NULL) { /* No arguments */
+ genop_W(s, OP_ENTER, 0); /* Generate OP_ENTER with no argument specification. */
s->ainfo = 0;
}
- else {
+ else { /* Has arguments */
mrb_aspec a;
int ma, oa, ra, pa, ka, kd, ba, i;
uint32_t pos;
node *opt;
node *margs, *pargs;
- node *tail;
+
+ /* args is already struct mrb_ast_args * */
/* mandatory arguments */
- ma = node_len(tree->car->car);
- margs = tree->car->car;
- tail = tree->car->cdr->cdr->cdr->cdr;
+ ma = node_len(args->mandatory_args);
+ margs = args->mandatory_args;
/* optional arguments */
- oa = node_len(tree->car->cdr->car);
+ oa = node_len(args->optional_args);
/* rest argument? */
- ra = tree->car->cdr->cdr->car ? 1 : 0;
+ ra = args->rest_arg ? 1 : 0;
/* mandatory arguments after rest argument */
- pa = node_len(tree->car->cdr->cdr->cdr->car);
- pargs = tree->car->cdr->cdr->cdr->car;
+ pa = node_len(args->post_mandatory_args);
+ pargs = args->post_mandatory_args;
+
/* keyword arguments */
- ka = tail ? node_len(tail->cdr->car) : 0;
- /* keyword dictionary? */
- kd = tail && tail->cdr->cdr->car? 1 : 0;
- /* block argument? */
- ba = tail && tail->cdr->cdr->cdr->car ? 1 : 0;
+ ka = args->keyword_args ? node_len(args->keyword_args) : 0;
+ kd = args->kwrest_arg ? 1 : 0;
+ /* &nil: no block accepted (noblock flag in aspec) */
+ mrb_bool noblock = args->block_arg == MRB_SYM(nil);
+ ba = (args->block_arg && !noblock) ? 1 : 0;
if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) {
codegen_error(s, "too many formal arguments");
}
- /* (23bits = 5:5:1:5:5:1:1) */
- a = MRB_ARGS_REQ(ma)
+ /* (24bits = 1:5:5:1:5:5:1:1) */
+ a = (noblock ? MRB_ARGS_NOBLOCK() : 0)
+ | MRB_ARGS_REQ(ma)
| MRB_ARGS_OPT(oa)
| (ra ? MRB_ARGS_REST() : 0)
| MRB_ARGS_POST(pa)
| MRB_ARGS_KEY(ka, kd)
| (ba ? MRB_ARGS_BLOCK() : 0);
genop_W(s, OP_ENTER, a);
- /* (12bits = 5:1:5:1) */
+ /* (13bits = 6:1:5:1:1) - Store argument counts for block argument passing (OP_BLKPUSH) */
s->ainfo = (((ma+oa) & 0x3f) << 7)
| ((ra & 0x1) << 6)
| ((pa & 0x1f) << 1)
- | (ka || kd);
- /* generate jump table for optional arguments initializer */
- pos = new_label(s);
+ | (ka || kd)
+ | ((ba & 0x1) << 13);
+
+ /* Optional argument default value initialization */
+ pos = new_label(s); /* Start of the optional argument jump table. */
for (i=0; i<oa; i++) {
new_label(s);
- genjmp_0(s, OP_JMP);
+ genjmp_0(s, OP_JMP); /* Placeholder jump for each optional arg. */
}
if (oa > 0) {
- genjmp_0(s, OP_JMP);
+ genjmp_0(s, OP_JMP); /* Jump to skip all default assignments if all optional args are provided. */
}
- opt = tree->car->cdr->car;
+ opt = args->optional_args; /* AST node for optional arguments. */
i = 0;
- while (opt) {
+ while (opt) { /* Iterate through optional arguments. */
int idx;
- mrb_sym id = nsym(opt->car->car);
+ mrb_sym id = node_to_sym(opt->car->car); /* Symbol of the optional argument. */
- dispatch(s, pos+i*3+1);
- codegen(s, opt->car->cdr, VAL);
+ dispatch(s, pos+i*3+1); /* Patch the jump to this argument's default value code. */
+ codegen(s, opt->car->cdr, VAL); /* Generate code for the default value expression. */
pop();
- idx = lv_idx(s, id);
+ idx = lv_idx(s, id); /* Get local variable index. */
if (idx > 0) {
- gen_move(s, idx, cursp(), 0);
+ gen_move(s, idx, cursp(), 0); /* Move default value to the local variable. */
}
- else {
+ else { /* Should not happen for optional args, but handle as upvar if it does. */
gen_getupvar(s, cursp(), id);
}
i++;
opt = opt->cdr;
}
if (oa > 0) {
- dispatch(s, pos+i*3+1);
+ dispatch(s, pos+i*3+1); /* Patch the final jump to after all default assignments. */
}
- /* keyword arguments */
- if (tail) {
- node *kwds = tail->cdr->car;
- int kwrest = 0;
+ /* Keyword argument processing */
+ if (ka > 0 || kd > 0) { /* Has keyword arguments or keyword rest */
+ node *kwds;
+ int kwrest = kd; /* Flag for keyword rest argument (e.g., **kwargs) */
- if (tail->cdr->cdr->car) {
- kwrest = 1;
- }
- mrb_assert(nint(tail->car) == NODE_ARGS_TAIL);
- mrb_assert(node_len(tail) == 4);
+ kwds = args->keyword_args;
while (kwds) {
int jmpif_key_p, jmp_def_set = -1;
- node *kwd = kwds->car, *def_arg = kwd->cdr->cdr->car;
- mrb_sym kwd_sym = nsym(kwd->cdr->car);
-
- mrb_assert(nint(kwd->car) == NODE_KW_ARG);
+ node *kwd = kwds->car;
+ mrb_sym kwd_sym = node_to_sym(kwd->car); /* Direct access to key */
+ node *def_arg = kwd->cdr; /* Direct access to value */
if (def_arg) {
int idx;
- genop_2(s, OP_KEY_P, lv_idx(s, kwd_sym), new_sym(s, kwd_sym));
+ genop_2(s, OP_KEY_P, lv_idx(s, kwd_sym), sym_idx(s, kwd_sym));
jmpif_key_p = genjmp2_0(s, OP_JMPIF, lv_idx(s, kwd_sym), NOVAL);
codegen(s, def_arg, VAL);
pop();
@@ -1585,7 +2484,7 @@ lambda_body(codegen_scope *s, node *tree, int blk)
jmp_def_set = genjmp_0(s, OP_JMP);
dispatch(s, jmpif_key_p);
}
- genop_2(s, OP_KARG, lv_idx(s, kwd_sym), new_sym(s, kwd_sym));
+ genop_2(s, OP_KARG, lv_idx(s, kwd_sym), sym_idx(s, kwd_sym));
if (jmp_def_set != -1) {
dispatch(s, jmp_def_set);
}
@@ -1593,39 +2492,113 @@ lambda_body(codegen_scope *s, node *tree, int blk)
kwds = kwds->cdr;
}
- if (tail->cdr->car && !kwrest) {
- genop_0(s, OP_KEYEND);
- }
- if (ba) {
- mrb_sym bparam = nsym(tail->cdr->cdr->cdr->car);
- pos = ma+oa+ra+pa+(ka||kd);
- if (bparam) {
- int idx = lv_idx(s, bparam);
- genop_2(s, OP_MOVE, idx, pos+1);
+ /* Check if there are keyword args but no keyword rest */
+ int has_keywords = args->keyword_args != NULL;
+
+ if (has_keywords && !kwrest) { /* If there are keyword args but no keyword rest. */
+ genop_0(s, OP_KEYEND); /* Signal end of keyword arguments. */
+
+ /* Reconstruct keyword hash for super to use */
+ /* After KEYEND, the hash at kw_pos is empty (all keys deleted by KARG) */
+ /* Build a fresh hash from the extracted keyword local variables */
+ int kw_dict_pos = ma + oa + ra + pa + 1;
+ int sp_save = cursp();
+
+ /* Load key-value pairs for each keyword argument starting at stack position */
+ node *kw_list = args->keyword_args;
+ int num_pairs = 0;
+ while (kw_list) {
+ node *kw = kw_list->car;
+ mrb_sym kw_sym = node_to_sym(kw->car);
+
+ /* Load symbol (key) */
+ genop_2(s, OP_LOADSYM, cursp(), sym_idx(s, kw_sym));
+ push();
+
+ /* Load keyword local variable value */
+ genop_2(s, OP_MOVE, cursp(), lv_idx(s, kw_sym));
+ push();
+
+ num_pairs++;
+ kw_list = kw_list->cdr;
+ }
+
+ /* Create hash at current stack position, then move to keyword dict position */
+ if (num_pairs > 0) {
+ genop_2(s, OP_HASH, sp_save, num_pairs);
+ genop_2(s, OP_MOVE, kw_dict_pos, sp_save);
}
+ else {
+ /* No keyword args, create empty hash */
+ genop_2(s, OP_HASH, sp_save, 0);
+ genop_2(s, OP_MOVE, kw_dict_pos, sp_save);
+ }
+
+ /* Restore stack pointer */
+ s->sp = sp_save;
}
}
- /* argument destructuring */
- if (margs) {
- node *n = margs;
+ /* Block argument processing */
+ if (ba) { /* If a block argument (e.g., &blk) is present. */
+ mrb_sym bparam = args->block_arg;
+ pos = ma+oa+ra+pa+(ka||kd); /* Calculate register offset for the block parameter. */
+ if (bparam) { /* If it's a named block parameter. */
+ int idx = lv_idx(s, bparam);
+ genop_2(s, OP_MOVE, idx, pos+1); /* Move the block from its argument slot to the local variable. */
+ }
+ }
- pos = 1;
+ /* Argument destructuring for mandatory and post-mandatory arguments */
+ if (margs) { /* Mandatory arguments */
+ node *n = margs;
+ pos = 1; /* Start from register 1 (after self). */
while (n) {
- if (nint(n->car->car) == NODE_MASGN) {
- gen_massignment(s, n->car->cdr->car, pos, NOVAL);
+ if (node_type(n->car) == NODE_MARG) { /* If the argument is a mass assignment (e.g., |(a,b)| ). */
+ struct mrb_ast_masgn_node *masgn_n = (struct mrb_ast_masgn_node*)n->car;
+ /* Use dedicated parameter destructuring logic instead of general codegen_masgn */
+ int nn = 0;
+ /* Handle pre variables */
+ if (masgn_n->pre) {
+ node *pre = masgn_n->pre;
+ while (pre) {
+ int sp = cursp();
+ genop_3(s, OP_AREF, sp, pos, nn);
+ push();
+ gen_assignment(s, pre->car, NULL, sp, NOVAL);
+ pop();
+ nn++;
+ pre = pre->cdr;
+ }
+ }
+ /* For now, only handle simple pre variables - rest/post would need more complex logic */
}
pos++;
n = n->cdr;
}
}
- if (pargs) {
+ if (pargs) { /* Post-mandatory arguments */
node *n = pargs;
-
- pos = ma+oa+ra+1;
+ pos = ma+oa+ra+1; /* Calculate starting register for post-mandatory args. */
while (n) {
- if (nint(n->car->car) == NODE_MASGN) {
- gen_massignment(s, n->car->cdr->car, pos, NOVAL);
+ if (node_type(n->car) == NODE_MARG) { /* If argument is a mass assignment. */
+ struct mrb_ast_masgn_node *masgn_n = (struct mrb_ast_masgn_node*)n->car;
+ /* Use dedicated parameter destructuring logic instead of general codegen_masgn */
+ int nn = 0;
+ /* Handle pre variables */
+ if (masgn_n->pre) {
+ node *pre = masgn_n->pre;
+ while (pre) {
+ int sp = cursp();
+ genop_3(s, OP_AREF, sp, pos, nn);
+ push();
+ gen_assignment(s, pre->car, NULL, sp, NOVAL);
+ pop();
+ nn++;
+ pre = pre->cdr;
+ }
+ }
+ /* For now, only handle simple pre variables - rest/post would need more complex logic */
}
pos++;
n = n->cdr;
@@ -1633,59 +2606,166 @@ lambda_body(codegen_scope *s, node *tree, int blk)
}
}
- codegen(s, tree->cdr->car, VAL);
- pop();
- if (s->pc > 0) {
+ /* Generate code for the actual body of the lambda/block. */
+ codegen(s, body, VAL);
+ pop(); /* Pop the result of the body. */
+
+ /* Implicit return of the last evaluated expression. */
+ if (s->pc > 0) { /* Ensure there's some code before adding return. */
gen_return(s, OP_RETURN, cursp());
}
+
if (blk) {
- loop_pop(s, NOVAL);
+ loop_pop(s, NOVAL); /* Pop the LOOP_BLOCK structure. */
}
- scope_finish(s);
- return parent->irep->rlen - 1;
+ scope_finish(s); /* Finalize the IREP for this lambda/block. */
+ return parent->irep->rlen - 1; /* Return the index of this IREP in the parent's REP list. */
}
+/*
+ * Generates code for a new lexical scope, typically for class/module definitions
+ * or the top-level script.
+ *
+ * This function handles the creation of a new `codegen_scope`, recursively
+ * generates code for the body of that scope, and then finalizes the scope
+ * to produce an `mrb_irep`.
+ *
+ * @param s The parent code generation scope.
+ * @param tree The AST node representing the scope.
+ * `tree->car` contains the list of local variables for the new scope.
+ * `tree->cdr` is the body (sequence of expressions) of the scope.
+ * @param val Unused in this specific function's direct logic for return value,
+ * but passed to `codegen` for the body.
+ * @return The index of the newly created `mrb_irep` in the parent scope's `reps` array.
+ * Returns 0 if `s->irep` is NULL (should not happen in normal operation).
+ */
static int
-scope_body(codegen_scope *s, node *tree, int val)
+scope_body(codegen_scope *s, node *locals, node *body, int val)
{
- codegen_scope *scope = scope_new(s->mrb, s, tree->car);
+ /* Create a new scope, inheriting from `s`, with local variables from `locals`. */
+ codegen_scope *scope = scope_new(s->mrb, s, locals);
+
+ /* Generate code for the body of the scope. */
+ codegen(scope, body, val);
- codegen(scope, tree->cdr, VAL);
- gen_return(scope, OP_RETURN, scope->sp-1);
- if (!s->iseq) {
+ /* If this is the outermost scope (e.g., top-level script), add OP_STOP. */
+ if (!s->iseq) { /* s->iseq would be NULL for the initial dummy scope. */
+ if (val) {
+ gen_return(scope, OP_RETURN, scope->sp-1);
+ }
+ /* skip RETURN when no_return_value; STOP will terminate VM */
genop_0(scope, OP_STOP);
}
+ else {
+ /* Ensure the scope returns the value of its last expression. */
+ if (val) {
+ gen_return(scope, OP_RETURN, scope->sp-1);
+ }
+ else {
+ gen_return(scope, OP_RETURN, 0); /* return nil */
+ }
+ }
+
+ /* Finalize the IREP for this scope. */
scope_finish(scope);
+
if (!s->irep) {
- /* should not happen */
+ /* This case should ideally not be reached in normal compilation. */
return 0;
}
+ /* Return the index of the newly created IREP in the parent's list of REPs. */
return s->irep->rlen - 1;
}
+static struct mrb_ast_var_header*
+get_var_header(node *n)
+{
+ if (!n) return NULL;
+
+ /* Try to interpret as variable-sized node */
+ struct mrb_ast_var_header *header = (struct mrb_ast_var_header*)n;
+ return header;
+}
+
+/* Helper to detect splat nodes in variable-sized format */
+static mrb_bool
+is_splat_node(node *n)
+{
+ return (node_type(n) == NODE_SPLAT);
+}
+
static mrb_bool
nosplat(node *t)
{
while (t) {
- if (nint(t->car->car) == NODE_SPLAT) return FALSE;
+ if (is_splat_node(t->car)) return FALSE;
t = t->cdr;
}
return TRUE;
}
+/* Check if node is a simple literal that can be generated into any register */
+static mrb_bool
+is_simple_literal(node *n)
+{
+ switch (node_type(n)) {
+ case NODE_INT:
+ case NODE_NIL:
+ case NODE_TRUE:
+ case NODE_FALSE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/* Check if all lhs are local variables and get their registers */
+static mrb_bool
+all_lvar_pre(codegen_scope *s, node *pre, int *regs, int max)
+{
+ int i = 0;
+ while (pre && i < max) {
+ if (node_type(pre->car) != NODE_LVAR) return FALSE;
+ int idx = lv_idx(s, var_node(pre->car)->symbol);
+ if (idx <= 0) return FALSE; /* not a local variable */
+ regs[i++] = idx;
+ pre = pre->cdr;
+ }
+ return pre == NULL; /* all processed */
+}
+
+/* Generate a simple literal directly into a specific register */
+static void
+gen_literal_to_reg(codegen_scope *s, node *n, int reg)
+{
+ switch (node_type(n)) {
+ case NODE_INT:
+ gen_int(s, reg, int_node(n)->value);
+ break;
+ case NODE_NIL:
+ genop_1(s, OP_LOADNIL, reg);
+ break;
+ case NODE_TRUE:
+ genop_1(s, OP_LOADTRUE, reg);
+ break;
+ case NODE_FALSE:
+ genop_1(s, OP_LOADFALSE, reg);
+ break;
+ default:
+ break;
+ }
+}
+
static mrb_sym
attrsym(codegen_scope *s, mrb_sym a)
{
- const char *name;
mrb_int len;
- char *name2;
-
- name = mrb_sym_name_len(s->mrb, a, &len);
- name2 = (char*)codegen_palloc(s,
- (size_t)len
- + 1 /* '=' */
- + 1 /* '\0' */
- );
+ const char *name = mrb_sym_name_len(s->mrb, a, &len);
+ char *name2 = (char*)codegen_palloc(s,
+ (size_t)len
+ + 1 /* '=' */
+ + 1 /* '\0' */
+ );
mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
memcpy(name2, name, (size_t)len);
name2[len] = '=';
@@ -1694,8 +2774,11 @@ attrsym(codegen_scope *s, mrb_sym a)
return mrb_intern(s->mrb, name2, len+1);
}
+/* Maximum number of arguments for a call that can be encoded directly in some opcodes (e.g. OP_SEND). */
#define CALL_MAXARGS 15
+/* Maximum number of elements in a literal array/hash handled by simpler opcodes before needing OP_ARYPUSH/OP_HASHADD. */
#define GEN_LIT_ARY_MAX 64
+/* Stack pointer threshold during value sequence generation; if cursp() exceeds this, intermediate arrays might be formed. */
#define GEN_VAL_STACK_MAX 99
static int
@@ -1718,7 +2801,45 @@ gen_values(codegen_scope *s, node *t, int val, int limit)
}
while (t) {
- int is_splat = nint(t->car->car) == NODE_SPLAT;
+ int is_splat = is_splat_node(t->car);
+
+ /* Optimization: skip or inline literal splat arrays
+ * - Empty splat (`*[]`/`*zarray`): contributes nothing; skip.
+ * - Non-empty literal array with no inner splat (`*[a,b]`): inline
+ * as normal positional args to avoid building/concatenating arrays.
+ */
+ if (is_splat) {
+ struct mrb_ast_splat_node *splat = splat_node(t->car);
+ node *sv = splat->value;
+ if (sv) {
+ enum node_type nt = node_type(sv);
+ if (nt == NODE_ARRAY) {
+ struct mrb_ast_array_node *an = array_node(sv);
+ if (an->elements == NULL) {
+ /* empty splat; contributes nothing */
+ t = t->cdr;
+ continue;
+ }
+ else if (nosplat(an->elements)) {
+ /* Inline non-empty literal array elements as regular args */
+ node *e = an->elements;
+ while (e) {
+ /* Honor evaluation order */
+ codegen(s, e->car, val);
+ n++;
+ e = e->cdr;
+ }
+ t = t->cdr;
+ continue;
+ }
+ }
+ else if (nt == NODE_ZARRAY) {
+ /* explicit empty array literal */
+ t = t->cdr;
+ continue;
+ }
+ }
+ }
if (is_splat || cursp() >= slimit) { /* flush stack */
pop_n(n);
@@ -1777,7 +2898,7 @@ gen_hash(codegen_scope *s, node *tree, int val, int limit)
mrb_bool first = TRUE;
while (tree) {
- if (nint(tree->car->car->car) == NODE_KW_REST_ARGS) {
+ if (node_to_sym(tree->car->car) == MRB_OPSYM(pow)) {
if (val && first) {
genop_2(s, OP_HASH, cursp(), 0);
push();
@@ -1841,306 +2962,143 @@ gen_hash(codegen_scope *s, node *tree, int val, int limit)
return len;
}
+
static void
-gen_call(codegen_scope *s, node *tree, int val, int safe)
+gen_colon_assign_common(codegen_scope *s, node *rhs, int sp, int val, int idx, int final_op)
{
- mrb_sym sym = nsym(tree->cdr->car);
- int skip = 0, n = 0, nk = 0, noop = no_optimize(s), noself = 0, blk = 0, sp_save = cursp();
- enum mrb_insn opt_op = OP_NOP;
-
- if (!noop) {
- if (sym == MRB_OPSYM_2(s->mrb, add)) opt_op = OP_ADD;
- else if (sym == MRB_OPSYM_2(s->mrb, sub)) opt_op = OP_SUB;
- else if (sym == MRB_OPSYM_2(s->mrb, mul)) opt_op = OP_MUL;
- else if (sym == MRB_OPSYM_2(s->mrb, div)) opt_op = OP_DIV;
- else if (sym == MRB_OPSYM_2(s->mrb, lt)) opt_op = OP_LT;
- else if (sym == MRB_OPSYM_2(s->mrb, le)) opt_op = OP_LE;
- else if (sym == MRB_OPSYM_2(s->mrb, gt)) opt_op = OP_GT;
- else if (sym == MRB_OPSYM_2(s->mrb, ge)) opt_op = OP_GE;
- else if (sym == MRB_OPSYM_2(s->mrb, eq)) opt_op = OP_EQ;
- else if (sym == MRB_OPSYM_2(s->mrb, aref)) opt_op = OP_GETIDX;
- else if (sym == MRB_OPSYM_2(s->mrb, aset)) opt_op = OP_SETIDX;
- }
- if (!tree->car || (opt_op == OP_NOP && nint(tree->car->car) == NODE_SELF)) {
- noself = 1;
- push();
- }
- else {
- codegen(s, tree->car, VAL); /* receiver */
+ if (rhs) {
+ codegen(s, rhs, VAL);
+ pop();
+ gen_move(s, sp, cursp(), 0);
}
- if (safe) {
- int recv = cursp()-1;
- gen_move(s, cursp(), recv, 1);
- skip = genjmp2_0(s, OP_JMPNIL, cursp(), val);
+ pop(); pop();
+ genop_2(s, final_op, cursp(), idx);
+ if (val) push();
+}
+
+static void
+gen_colon2_assign(codegen_scope *s, node *varnode, node *rhs, int sp, int val)
+{
+ struct mrb_ast_colon2_node *n = (struct mrb_ast_colon2_node*)varnode;
+ int idx;
+
+ if (sp) {
+ gen_move(s, cursp(), sp, 0);
}
- tree = tree->cdr->cdr->car;
- if (tree) {
- if (tree->car) { /* positional arguments */
- n = gen_values(s, tree->car, VAL, 14);
- if (n < 0) { /* variable length */
- noop = 1; /* not operator */
- n = 15;
- push();
- }
- }
- if (tree->cdr->car) { /* keyword arguments */
- noop = 1;
- nk = gen_hash(s, tree->cdr->car->cdr, VAL, 14);
- if (nk < 0) nk = 15;
- }
+ sp = cursp();
+ push();
+ codegen(s, n->base, VAL);
+ idx = sym_idx(s, n->name);
+ gen_colon_assign_common(s, rhs, sp, val, idx, OP_SETMCNST);
+}
+
+static void
+gen_colon3_assign(codegen_scope *s, node *varnode, node *rhs, int sp, int val)
+{
+ struct mrb_ast_colon3_node *n = (struct mrb_ast_colon3_node*)varnode;
+ int idx;
+
+ if (sp) {
+ gen_move(s, cursp(), sp, 0);
}
- if (tree && tree->cdr && tree->cdr->cdr) {
- codegen(s, tree->cdr->cdr, VAL);
+ sp = cursp();
+ push();
+ genop_1(s, OP_OCLASS, cursp());
+ push();
+ idx = sym_idx(s, n->name);
+ gen_colon_assign_common(s, rhs, sp, val, idx, OP_SETCONST);
+}
+
+static void
+gen_xvar_assignment(codegen_scope *s, node *tree, node *rhs, int sp, int val, uint8_t op)
+{
+ struct mrb_ast_var_node *var = (struct mrb_ast_var_node*)tree;
+ if (rhs) {
+ codegen(s, rhs, VAL);
pop();
- noop = 1;
- blk = 1;
+ sp = cursp();
}
+ gen_setxv(s, op, sp, var->symbol, val);
+}
+
+static void
+gen_xvar(codegen_scope *s, mrb_sym sym, int val, uint8_t op)
+{
+ if (!val) return;
+ int i = sym_idx(s, sym);
+
+ genop_2(s, op, cursp(), i);
push();
- s->sp = sp_save;
- if (opt_op == OP_ADD && n == 1) {
- gen_addsub(s, OP_ADD, cursp());
- }
- else if (opt_op == OP_SUB && n == 1) {
- gen_addsub(s, OP_SUB, cursp());
- }
- else if (opt_op == OP_MUL && n == 1) {
- gen_muldiv(s, OP_MUL, cursp());
- }
- else if (opt_op == OP_DIV && n == 1) {
- gen_muldiv(s, OP_DIV, cursp());
- }
- else if (opt_op == OP_LT && n == 1) {
- genop_1(s, OP_LT, cursp());
- }
- else if (opt_op == OP_LE && n == 1) {
- genop_1(s, OP_LE, cursp());
- }
- else if (opt_op == OP_GT && n == 1) {
- genop_1(s, OP_GT, cursp());
- }
- else if (opt_op == OP_GE && n == 1) {
- genop_1(s, OP_GE, cursp());
- }
- else if (opt_op == OP_EQ && n == 1) {
- genop_1(s, OP_EQ, cursp());
- }
- else if (opt_op == OP_SETIDX && n == 2) {
- genop_1(s, OP_SETIDX, cursp());
- }
- else if (!noop && n == 0 && gen_uniop(s, sym, cursp())) {
- /* constant folding succeeded */
- }
- else if (!noop && n == 1 && gen_binop(s, sym, cursp())) {
- /* constant folding succeeded */
- }
- else if (noself) {
- genop_3(s, blk ? OP_SSENDB : OP_SSEND, cursp(), new_sym(s, sym), n|(nk<<4));
- }
- else {
- genop_3(s, blk ? OP_SENDB : OP_SEND, cursp(), new_sym(s, sym), n|(nk<<4));
- }
- if (safe) {
- dispatch(s, skip);
- }
- if (val) {
- push();
- }
}
static void
gen_assignment(codegen_scope *s, node *tree, node *rhs, int sp, int val)
{
int idx;
- int type = nint(tree->car);
- switch (type) {
- case NODE_GVAR:
- case NODE_ARG:
- case NODE_LVAR:
- case NODE_IVAR:
- case NODE_CVAR:
- case NODE_CONST:
+ /* Check if this is a variable-sized node first */
+ enum node_type var_type = node_type(tree);
+ switch (var_type) {
case NODE_NIL:
- case NODE_MASGN:
if (rhs) {
codegen(s, rhs, VAL);
pop();
sp = cursp();
}
+ /* NODE_NIL assignment is complete - just break (splat without assignment) */
break;
-
case NODE_COLON2:
+ gen_colon2_assign(s, tree, rhs, sp, val);
+ return;
case NODE_COLON3:
- case NODE_CALL:
- case NODE_SCALL:
- /* keep evaluation order */
- break;
-
- case NODE_NVAR:
- /* never happens; should have already checked in the parser */
- codegen_error(s, "Can't assign to numbered parameter");
- break;
-
- default:
- codegen_error(s, "unknown lhs");
- break;
- }
-
- tree = tree->cdr;
- switch (type) {
+ gen_colon3_assign(s, tree, rhs, sp, val);
+ return;
case NODE_GVAR:
- gen_setxv(s, OP_SETGV, sp, nsym(tree), val);
- break;
- case NODE_ARG:
- case NODE_LVAR:
- idx = lv_idx(s, nsym(tree));
- if (idx > 0) {
- if (idx != sp) {
- gen_move(s, idx, sp, val);
- }
- break;
- }
- else { /* upvar */
- gen_setupvar(s, sp, nsym(tree));
- }
+ gen_xvar_assignment(s, tree, rhs, sp, val, OP_SETGV);
break;
case NODE_IVAR:
- gen_setxv(s, OP_SETIV, sp, nsym(tree), val);
+ gen_xvar_assignment(s, tree, rhs, sp, val, OP_SETIV);
break;
case NODE_CVAR:
- gen_setxv(s, OP_SETCV, sp, nsym(tree), val);
+ gen_xvar_assignment(s, tree, rhs, sp, val, OP_SETCV);
break;
case NODE_CONST:
- gen_setxv(s, OP_SETCONST, sp, nsym(tree), val);
+ gen_xvar_assignment(s, tree, rhs, sp, val, OP_SETCONST);
break;
- case NODE_COLON2:
- case NODE_COLON3:
- if (sp) {
- gen_move(s, cursp(), sp, 0);
- }
- sp = cursp();
- push();
- if (type == NODE_COLON2) {
- codegen(s, tree->car, VAL);
- idx = new_sym(s, nsym(tree->cdr));
- }
- else { /* NODE_COLON3 */
- genop_1(s, OP_OCLASS, cursp());
- push();
- idx = new_sym(s, nsym(tree));
- }
- if (rhs) {
- codegen(s, rhs, VAL); pop();
- gen_move(s, sp, cursp(), 0);
- }
- pop_n(2);
- genop_2(s, OP_SETMCNST, sp, idx);
- break;
-
- case NODE_CALL:
- case NODE_SCALL:
+ case NODE_MASGN:
+ case NODE_MARG:
+ /* Multiple assignment: expressions (MASGN) and parameter destructuring (MARG) */
+ codegen_masgn(s, tree, rhs, sp, val);
+ return;
+ case NODE_LVAR:
{
- int noself = 0, safe = (type == NODE_SCALL), skip = 0, top, call, n = 0;
- mrb_sym mid = nsym(tree->cdr->car);
-
- top = cursp();
- if (val || sp == cursp()) {
- push(); /* room for retval */
- }
- call = cursp();
- if (!tree->car) {
- noself = 1;
- push();
- }
- else {
- codegen(s, tree->car, VAL); /* receiver */
- }
- if (safe) {
- int recv = cursp()-1;
- gen_move(s, cursp(), recv, 1);
- skip = genjmp2_0(s, OP_JMPNIL, cursp(), val);
- }
- tree = tree->cdr->cdr->car;
- if (tree) {
- if (tree->car) { /* positional arguments */
- n = gen_values(s, tree->car, VAL, (tree->cdr->car)?13:14);
- if (n < 0) { /* variable length */
- n = 15;
- push();
- }
- }
- if (tree->cdr->car) { /* keyword arguments */
- if (n == 13 || n == 14) {
- pop_n(n);
- genop_2(s, OP_ARRAY, cursp(), n);
- push();
- n = 15;
- }
- gen_hash(s, tree->cdr->car->cdr, VAL, 0);
- if (n < 14) {
- n++;
- }
- else {
- pop_n(2);
- genop_2(s, OP_ARYPUSH, cursp(), 1);
- }
- push();
- }
- }
+ mrb_sym sym = var_node(tree)->symbol;
if (rhs) {
codegen(s, rhs, VAL);
pop();
+ sp = cursp();
}
- else {
- gen_move(s, cursp(), sp, 0);
- }
- if (val) {
- gen_move(s, top, cursp(), 1);
- }
- if (n < 15) {
- n++;
- if (n == 15) {
- pop_n(14);
- genop_2(s, OP_ARRAY, cursp(), 15);
+ idx = lv_idx(s, sym);
+ if (idx > 0) {
+ if (idx != sp) {
+ gen_move(s, idx, sp, val);
}
+ break;
}
else {
- pop();
- genop_2(s, OP_ARYPUSH, cursp(), 1);
- }
- push(); pop();
- s->sp = call;
- if (mid == MRB_OPSYM_2(s->mrb, aref) && n == 2) {
- push_n(4); pop_n(4); /* self + idx + value + (invisible block for OP_SEND) */
- genop_1(s, OP_SETIDX, cursp());
- }
- else {
- int st = 2 /* self + block */ +
- (((n >> 0) & 0x0f) < 15 ? ((n >> 0) & 0x0f) : 1) +
- (((n >> 4) & 0x0f) < 15 ? ((n >> 4) & 0x0f) * 2 : 1);
- push_n(st); pop_n(st);
- genop_3(s, noself ? OP_SSEND : OP_SEND, cursp(), new_sym(s, attrsym(s, mid)), n);
- }
- if (safe) {
- dispatch(s, skip);
+ gen_setupvar(s, sp, sym);
}
- s->sp = top;
}
break;
-
- case NODE_MASGN:
- gen_massignment(s, tree->car, sp, val);
- break;
-
- /* splat without assignment */
- case NODE_NIL:
- break;
-
+ case NODE_CALL:
+ codegen_call_assign(s, tree, rhs, sp, val);
+ return;
default:
- codegen_error(s, "unknown lhs");
+ codegen_error(s, "unsupported variable-sized lhs");
break;
}
if (val) push();
+ return;
}
static void
@@ -2216,71 +3174,136 @@ static void
gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val)
{
if (val) {
- int i = 0, j = 0, gen = 0;
-
- while (tree) {
- switch (nint(tree->car->car)) {
- case NODE_STR:
- if ((tree->cdr == NULL) && (nint(tree->car->cdr->cdr) == 0))
- break;
- /* fall through */
- case NODE_BEGIN:
- codegen(s, tree->car, VAL);
- j++;
- break;
+ int array_size = 0;
+ int first = 1;
+ int slimit = GEN_LIT_ARY_MAX;
+ node *current = tree;
+
+ if (cursp() >= slimit) slimit = GEN_VAL_STACK_MAX;
+
+ /* Process each segment separated by NODE_LITERAL_DELIM */
+ while (current) {
+ /* Find the segment boundaries without allocating */
+ node *segment_start = current;
+ node *segment_prev = NULL;
+
+ /* Find end of segment (delimiter or end of list) */
+ while (current && !IS_LITERAL_DELIM(current)) {
+ segment_prev = current;
+ current = current->cdr;
+ }
+
+ /* Process the segment if it has content */
+ if (segment_start != current) {
+ /* Check if this is an empty string segment (for %w[] case) */
+ mrb_bool is_empty_segment = TRUE;
+ node *check = segment_start;
+ while (check != current) {
+ if (check->car) {
+ mrb_int len = node_to_int(check->car->car);
+ if (len > 0) {
+ is_empty_segment = FALSE;
+ break;
+ }
+ else if (len < 0) {
+ /* Expression node - not empty */
+ is_empty_segment = FALSE;
+ break;
+ }
+ /* len == 0 means empty string, continue checking */
+ }
+ check = check->cdr;
+ }
+
+ /* Only process non-empty segments */
+ if (!is_empty_segment) {
+ /* Flush accumulated elements when stack is full */
+ if (cursp() >= slimit) {
+ if (array_size > 0) {
+ pop_n(array_size);
+ if (first) {
+ genop_2(s, OP_ARRAY, cursp(), array_size);
+ push();
+ first = 0;
+ }
+ else {
+ pop();
+ genop_2(s, OP_ARYPUSH, cursp(), array_size);
+ push();
+ }
+ array_size = 0;
+ }
+ }
+
+ /* Temporarily terminate the segment by saving and clearing the cdr */
+ node *saved_cdr = NULL;
+ if (segment_prev) {
+ saved_cdr = segment_prev->cdr;
+ segment_prev->cdr = NULL;
+ }
+
+ /* Use gen_string for this segment */
+ gen_string(s, segment_start, VAL);
+
+ /* Restore the original cdr */
+ if (segment_prev) {
+ segment_prev->cdr = saved_cdr;
+ }
- case NODE_LITERAL_DELIM:
- if (j > 0) {
- j = 0;
- i++;
- if (sym)
+ /* Apply symbol conversion if needed */
+ if (sym) {
gen_intern(s);
+ }
+
+ array_size++;
}
- break;
- }
- while (j >= 2) {
- pop(); pop();
- genop_1(s, OP_STRCAT, cursp());
- push();
- j--;
}
- if (i > GEN_LIT_ARY_MAX) {
- pop_n(i);
- if (gen) {
- pop();
- genop_2(s, OP_ARYPUSH, cursp(), i);
- }
- else {
- genop_2(s, OP_ARRAY, cursp(), i);
- gen = 1;
- }
- push();
- i = 0;
+
+ /* Skip the delimiter if present */
+ if (current && IS_LITERAL_DELIM(current)) {
+ current = current->cdr;
}
- tree = tree->cdr;
}
- if (j > 0) {
- i++;
- if (sym)
- gen_intern(s);
+
+ /* Handle remaining elements */
+ if (!first) {
+ if (array_size > 0) {
+ pop_n(array_size + 1);
+ genop_2(s, OP_ARYPUSH, cursp(), array_size);
+ }
}
- pop_n(i);
- if (gen) {
- pop();
- genop_2(s, OP_ARYPUSH, cursp(), i);
+ else if (array_size > 0) {
+ pop_n(array_size);
+ genop_2(s, OP_ARRAY, cursp(), array_size);
}
else {
- genop_2(s, OP_ARRAY, cursp(), i);
+ genop_2(s, OP_ARRAY, cursp(), 0);
}
push();
}
else {
- while (tree) {
- switch (nint(tree->car->car)) {
- case NODE_BEGIN: case NODE_BLOCK:
- codegen(s, tree->car, NOVAL);
+ /* NOVAL case: only evaluate expressions for side effects */
+ node *current = tree;
+
+ while (current) {
+ /* Process nodes until delimiter */
+ while (current && !IS_LITERAL_DELIM(current)) {
+ node *elem = current->car;
+ if (elem) {
+ mrb_int len = node_to_int(elem->car);
+ if (len < 0) {
+ /* Expression: (-1 . node) - evaluate for side effects */
+ codegen(s, (node*)elem->cdr, NOVAL);
+ }
+ /* String literals: (len . str) - no side effects, skip */
+ }
+ current = current->cdr;
+ }
+
+ /* Skip delimiter */
+ if (current && IS_LITERAL_DELIM(current)) {
+ current = current->cdr;
}
- tree = tree->cdr;
}
}
}
@@ -2293,56 +3316,10 @@ raise_error(codegen_scope *s, const char *msg)
genop_1(s, OP_ERR, idx);
}
-static mrb_int
-readint(codegen_scope *s, const char *p, int base, mrb_bool neg, mrb_bool *overflow)
-{
- const char *e = p + strlen(p);
- mrb_int result = 0;
-
- mrb_assert(base >= 2 && base <= 16);
- if (*p == '+') p++;
- while (p < e) {
- int n;
- char c = *p;
- switch (c) {
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- n = c - '0'; break;
- case '8': case '9':
- n = c - '0'; break;
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- n = c - 'a' + 10; break;
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- n = c - 'A' + 10; break;
- default:
- codegen_error(s, "malformed readint input");
- *overflow = TRUE;
- /* not reached */
- return result;
- }
- if (mrb_int_mul_overflow(result, base, &result)) {
- overflow:
- *overflow = TRUE;
- return 0;
- }
- mrb_uint tmp = ((mrb_uint)result)+n;
- if (neg && tmp == (mrb_uint)MRB_INT_MAX+1) {
- *overflow = FALSE;
- return MRB_INT_MIN;
- }
- if (tmp > MRB_INT_MAX) goto overflow;
- result = (mrb_int)tmp;
- p++;
- }
- *overflow = FALSE;
- if (neg) return -result;
- return result;
-}
-
static void
gen_retval(codegen_scope *s, node *tree)
{
- if (nint(tree->car) == NODE_SPLAT) {
+ if (is_splat_node(tree)) {
codegen(s, tree, VAL);
pop();
genop_1(s, OP_ARYSPLAT, cursp());
@@ -2356,11 +3333,13 @@ gen_retval(codegen_scope *s, node *tree)
static mrb_bool
true_always(node *tree)
{
- switch (nint(tree->car)) {
- case NODE_TRUE:
+ /* Check if this is a variable-sized node first */
+ enum node_type var_type = node_type(tree);
+ switch (var_type) {
case NODE_INT:
- case NODE_STR:
- case NODE_SYM:
+ case NODE_BIGINT:
+ case NODE_FLOAT:
+ case NODE_TRUE:
return TRUE;
default:
return FALSE;
@@ -2370,7 +3349,8 @@ true_always(node *tree)
static mrb_bool
false_always(node *tree)
{
- switch (nint(tree->car)) {
+ /* Check variable-sized nodes that are always false */
+ switch (node_type(tree)) {
case NODE_FALSE:
case NODE_NIL:
return TRUE;
@@ -2397,1557 +3377,3676 @@ gen_blkmove(codegen_scope *s, uint16_t ainfo, int lv)
}
static void
-codegen(codegen_scope *s, node *tree, int val)
+gen_lvar(codegen_scope *s, mrb_sym sym, int val)
{
- int nt;
- int rlev = s->rlev;
+ if (!val) return;
+ int idx = lv_idx(s, sym);
- if (!tree) {
- if (val) {
- genop_1(s, OP_LOADNIL, cursp());
- push();
- }
- return;
+ if (idx > 0) {
+ gen_move(s, cursp(), idx, val);
+ }
+ else {
+ gen_getupvar(s, cursp(), sym);
}
+ push();
+}
- s->rlev++;
- if (s->rlev > MRB_CODEGEN_LEVEL_MAX) {
- codegen_error(s, "too complex expression");
+static void
+codegen_hash(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_hash_node *hash = hash_node(varnode);
+ node *pairs = hash->pairs;
+ int regular_pairs = 0;
+ mrb_bool update = FALSE;
+ mrb_bool first = TRUE;
+
+ if (!val) return;
+
+ if (!pairs) {
+ genop_2(s, OP_HASH, cursp(), 0);
+ push();
+ return;
}
- if (s->irep && s->filename_index != tree->filename_index) {
- mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index);
- const char *filename = mrb_sym_name_len(s->mrb, fname, NULL);
- mrb_debug_info_append_file(s->mrb, s->irep->debug_info,
- filename, s->lines, s->debug_start_pos, s->pc);
- s->debug_start_pos = s->pc;
- s->filename_index = tree->filename_index;
- s->filename_sym = mrb_parser_get_filename(s->parser, tree->filename_index);
+ /* Process each key-value pair using cons-list iteration, handling double-splat (**) cases */
+ node *current = pairs;
+ while (current) {
+ /* Each current->car is a cons (key . value) */
+ node *pair = current->car;
+ struct mrb_ast_node *key = pair->car;
+ struct mrb_ast_node *value = pair->cdr;
+
+ /* Check if this is a double-splat (**kwargs) */
+ if (node_to_sym(key) == MRB_OPSYM(pow)) {
+ /* Flush any accumulated regular pairs first */
+ if (val && first && regular_pairs == 0) {
+ /* First element is splat - create empty hash */
+ genop_2(s, OP_HASH, cursp(), 0);
+ push();
+ update = TRUE;
+ }
+ else if (val && regular_pairs > 0) {
+ /* Create/add hash from accumulated pairs */
+ pop_n(regular_pairs * 2);
+ if (!update) {
+ genop_2(s, OP_HASH, cursp(), regular_pairs);
+ }
+ else {
+ pop();
+ genop_2(s, OP_HASHADD, cursp(), regular_pairs);
+ }
+ push();
+ }
+
+ /* Generate the splat hash */
+ codegen(s, value, val);
+
+ /* Merge the splat hash */
+ if (val && (regular_pairs > 0 || update)) {
+ pop(); pop();
+ genop_1(s, OP_HASHCAT, cursp());
+ push();
+ }
+
+ update = TRUE;
+ regular_pairs = 0;
+ }
+ else {
+ /* Regular key-value pair */
+ codegen(s, key, val);
+ codegen(s, value, val);
+ regular_pairs++;
+ }
+ first = FALSE;
+
+ current = current->cdr;
}
- nt = nint(tree->car);
- s->lineno = tree->lineno;
- tree = tree->cdr;
- switch (nt) {
- case NODE_BEGIN:
- if (val && !tree) {
- genop_1(s, OP_LOADNIL, cursp());
+ /* Handle any remaining regular pairs */
+ if (val) {
+ if (!update && regular_pairs > 0) {
+ /* Simple case: no splats, just create hash */
+ pop_n(regular_pairs * 2);
+ genop_2(s, OP_HASH, cursp(), regular_pairs);
push();
}
- while (tree) {
- codegen(s, tree->car, tree->cdr ? NOVAL : val);
- tree = tree->cdr;
+ else if (update && regular_pairs > 0) {
+ /* Add remaining pairs to existing hash */
+ pop_n(regular_pairs * 2 + 1);
+ genop_2(s, OP_HASHADD, cursp(), regular_pairs);
+ push();
}
- break;
+ }
+}
- case NODE_RESCUE:
- {
- int noexc;
- uint32_t exend, pos1, pos2, tmp;
- struct loopinfo *lp;
- int catch_entry, begin, end;
- if (tree->car == NULL) goto exit;
- lp = loop_push(s, LOOP_BEGIN);
- lp->pc0 = new_label(s);
- catch_entry = catch_handler_new(s);
- begin = s->pc;
- codegen(s, tree->car, VAL);
- pop();
- lp->type = LOOP_RESCUE;
- end = s->pc;
- noexc = genjmp_0(s, OP_JMP);
- catch_handler_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc);
- tree = tree->cdr;
- exend = JMPLINK_START;
- pos1 = JMPLINK_START;
- if (tree->car) {
- node *n2 = tree->car;
- int exc = cursp();
-
- genop_1(s, OP_EXCEPT, exc);
+
+/* Common function to generate bytecode for cons list string representation
+ * Handles list of elements where each element is either:
+ * - (len . str) for string literals
+ * - (-1 . node) for expressions that need evaluation
+ */
+/* Common function to generate bytecode for cons list string representation
+ * Handles list of elements where each element is either:
+ * - (len . str) for string literals
+ * - (-1 . node) for expressions that need evaluation
+ */
+/* Common function to generate bytecode for cons list string representation
+ * Handles list of elements where each element is either:
+ * - (len . str) for string literals
+ * - (-1 . node) for expressions that need evaluation
+ */
+/* Common function to generate bytecode for cons list string representation
+ * Handles list of elements where each element is either:
+ * - (len . str) for string literals
+ * - (-1 . node) for expressions that need evaluation
+ */
+static void
+gen_string(codegen_scope *s, node *list, int val)
+{
+ if (val) {
+ /* Handle as cons list of string parts with safety checks */
+ node *n = list;
+ mrb_bool first = TRUE;
+
+ while (n) {
+ node *elem = n->car;
+ if (!elem) break;
+
+ mrb_int len = node_to_int(elem->car);
+
+ if (len >= 0) {
+ /* String literal: (len . str) */
+ const char *str = (char*)elem->cdr;
+ if (!str) {str = ""; len = 0;}
+ int off = new_lit_str(s, str, len);
+ genop_2(s, OP_STRING, cursp(), off);
push();
- while (n2) {
- node *n3 = n2->car;
- node *n4 = n3->car;
-
- dispatch(s, pos1);
- pos2 = JMPLINK_START;
- do {
- if (n4 && n4->car && nint(n4->car->car) == NODE_SPLAT) {
- codegen(s, n4->car, VAL);
- gen_move(s, cursp(), exc, 0);
- push_n(2); pop_n(2); /* space for one arg and a block */
- pop();
- genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, __case_eqq)), 1);
- }
- else {
- if (n4) {
- codegen(s, n4->car, VAL);
- }
- else {
- genop_2(s, OP_GETCONST, cursp(), new_sym(s, MRB_SYM_2(s->mrb, StandardError)));
- push();
- }
- pop();
- genop_2(s, OP_RESCUE, exc, cursp());
- }
- tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, val);
- pos2 = tmp;
- if (n4) {
- n4 = n4->cdr;
- }
- } while (n4);
- pos1 = genjmp_0(s, OP_JMP);
- dispatch_linked(s, pos2);
+ }
+ else {
+ /* Expression: (-1 . node) */
+ codegen(s, (node*)elem->cdr, VAL);
+ }
- pop();
- if (n3->cdr->car) {
- gen_assignment(s, n3->cdr->car, NULL, exc, NOVAL);
- }
- if (n3->cdr->cdr->car) {
- codegen(s, n3->cdr->cdr->car, val);
- if (val) pop();
- }
- tmp = genjmp(s, OP_JMP, exend);
- exend = tmp;
- n2 = n2->cdr;
- push();
- }
- if (pos1 != JMPLINK_START) {
- dispatch(s, pos1);
- genop_1(s, OP_RAISEIF, exc);
- }
+ /* Concatenate with previous parts (except for first element) */
+ if (!first) {
+ pop(); pop();
+ genop_1(s, OP_STRCAT, cursp());
+ push();
}
- pop();
- tree = tree->cdr;
- dispatch(s, noexc);
- if (tree->car) {
- codegen(s, tree->car, val);
+ else {
+ first = FALSE;
}
- else if (val) {
+
+ n = n->cdr;
+ }
+
+ /* Handle empty list case */
+ if (first) {
+ gen_load_nil(s, 1);
+ }
+ }
+ else {
+ /* NOVAL case: only evaluate expressions for side effects */
+ node *n = list;
+ while (n) {
+ node *elem = n->car;
+ if (!elem) break;
+ if (node_to_int(elem->car) < 0) {
+ /* Expression: (-1 . node) - evaluate for side effects */
+ codegen(s, (node*)elem->cdr, NOVAL);
+ }
+ /* String literals: (len . str) - no side effects, skip */
+ n = n->cdr;
+ }
+ }
+}
+
+
+/* Handle variable-sized node types */
+static void
+codegen_call(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_call_node *call = call_node(varnode);
+ mrb_sym sym = call->method_name;
+ int skip = 0, n = 0, nk = 0, noop = no_optimize(s), noself = 0, blk = 0, sp_save = cursp();
+ enum mrb_insn opt_op = OP_NOP;
+ int safe = call->safe_call;
+ node *args = call->args;
+
+ if (!noop) {
+ if (sym == MRB_OPSYM(add)) opt_op = OP_ADD;
+ else if (sym == MRB_OPSYM(sub)) opt_op = OP_SUB;
+ else if (sym == MRB_OPSYM(mul)) opt_op = OP_MUL;
+ else if (sym == MRB_OPSYM(div)) opt_op = OP_DIV;
+ else if (sym == MRB_OPSYM(lt)) opt_op = OP_LT;
+ else if (sym == MRB_OPSYM(le)) opt_op = OP_LE;
+ else if (sym == MRB_OPSYM(gt)) opt_op = OP_GT;
+ else if (sym == MRB_OPSYM(ge)) opt_op = OP_GE;
+ else if (sym == MRB_OPSYM(eq)) opt_op = OP_EQ;
+ else if (sym == MRB_OPSYM(aref)) opt_op = OP_GETIDX;
+ else if (sym == MRB_OPSYM(aset)) opt_op = OP_SETIDX;
+ }
+
+ if (!call->receiver || (opt_op == OP_NOP && node_type(call->receiver) == NODE_SELF)) {
+ noself = 1;
+ push();
+ }
+ else {
+ codegen(s, call->receiver, VAL); /* receiver */
+ }
+
+ if (safe) {
+ int recv = cursp()-1;
+ gen_move(s, cursp(), recv, 1);
+ skip = genjmp2_0(s, OP_JMPNIL, cursp(), val);
+ }
+
+ /* Generate arguments - use gen_values to properly handle splat */
+ if (args) {
+ struct mrb_ast_callargs *callargs = (struct mrb_ast_callargs*)args;
+ if (callargs->regular_args) {
+ n = gen_values(s, callargs->regular_args, VAL, 14);
+ if (n < 0) { /* variable length (contains splat) */
+ n = 15;
push();
+ noop = 1;
}
- dispatch_linked(s, exend);
- loop_pop(s, NOVAL);
}
- break;
- case NODE_ENSURE:
- if (!tree->cdr || !tree->cdr->cdr ||
- (nint(tree->cdr->cdr->car) == NODE_BEGIN &&
- tree->cdr->cdr->cdr)) {
- int catch_entry, begin, end, target;
- int idx;
+ /* Handle keyword arguments if present */
+ if (callargs->keyword_args) {
+ nk = gen_hash(s, callargs->keyword_args, VAL, 14);
+ if (nk < 0) {
+ nk = 15;
+ }
+ noop = 1;
+ }
- catch_entry = catch_handler_new(s);
- begin = s->pc;
- codegen(s, tree->car, val);
- end = target = s->pc;
- push();
- idx = cursp();
- genop_1(s, OP_EXCEPT, idx);
- push();
- codegen(s, tree->cdr->cdr, NOVAL);
- pop();
- genop_1(s, OP_RAISEIF, idx);
+ /* Handle block if present */
+ if (callargs->block_arg) {
+ codegen(s, callargs->block_arg, VAL);
pop();
- catch_handler_set(s, catch_entry, MRB_CATCH_ENSURE, begin, end, target);
- }
- else { /* empty ensure ignored */
- codegen(s, tree->car, val);
+ blk = 1;
+ noop = 1;
}
- break;
+ }
- case NODE_LAMBDA:
- if (val) {
- int idx = lambda_body(s, tree, 1);
+ push();
+ s->sp = sp_save;
- genop_2(s, OP_LAMBDA, cursp(), idx);
- push();
+ /* Apply optimizations */
+ if (opt_op == OP_ADD && n == 1) {
+ gen_addsub(s, OP_ADD, cursp());
+ }
+ else if (opt_op == OP_SUB && n == 1) {
+ gen_addsub(s, OP_SUB, cursp());
+ }
+ else if (opt_op == OP_MUL && n == 1) {
+ gen_muldiv(s, OP_MUL, cursp());
+ }
+ else if (opt_op == OP_DIV && n == 1) {
+ gen_muldiv(s, OP_DIV, cursp());
+ }
+ else if (opt_op == OP_LT && n == 1) {
+ genop_1(s, OP_LT, cursp());
+ }
+ else if (opt_op == OP_LE && n == 1) {
+ genop_1(s, OP_LE, cursp());
+ }
+ else if (opt_op == OP_GT && n == 1) {
+ genop_1(s, OP_GT, cursp());
+ }
+ else if (opt_op == OP_GE && n == 1) {
+ genop_1(s, OP_GE, cursp());
+ }
+ else if (opt_op == OP_EQ && n == 1) {
+ genop_1(s, OP_EQ, cursp());
+ }
+ else if (opt_op == OP_SETIDX && n == 2) {
+ genop_1(s, OP_SETIDX, cursp());
+ }
+ else if (!noop && n == 0 && gen_uniop(s, sym, cursp())) {
+ /* constant folding succeeded */
+ }
+ else if (!noop && n == 1 && gen_binop(s, sym, cursp())) {
+ /* constant folding succeeded */
+ }
+ else if (noself) {
+ if (!blk && n == 0 && nk == 0) {
+ genop_2(s, OP_SSEND0, cursp(), sym_idx(s, sym));
}
- break;
+ else {
+ genop_3(s, blk ? OP_SSENDB : OP_SSEND, cursp(), sym_idx(s, sym), n|(nk<<4));
+ }
+ }
+ else if (!blk && n == 0 && nk == 0) {
+ genop_2(s, OP_SEND0, cursp(), sym_idx(s, sym));
+ }
+ else {
+ genop_3(s, blk ? OP_SENDB : OP_SEND, cursp(), sym_idx(s, sym), n|(nk<<4));
+ }
- case NODE_BLOCK:
- if (val) {
- int idx = lambda_body(s, tree, 1);
+ if (safe) {
+ dispatch(s, skip);
+ }
+ if (!val) return;
+ push();
+}
- genop_2(s, OP_BLOCK, cursp(), idx);
- push();
+static void
+codegen_call_assign(codegen_scope *s, node *varnode, node *rhs, int sp, int val)
+{
+ enum node_type var_type = NODE_TYPE(varnode);
+ int noself = 0, safe = 0, skip = 0, top, callsp, n = 0, nk = 0;
+ mrb_sym mid = 0;
+ node *args = NULL;
+ node *receiver = NULL;
+ enum mrb_insn opt_op = OP_NOP;
+ int noop = no_optimize(s);
+
+ /* Extract information based on node type */
+ if (var_type == NODE_CALL) {
+ struct mrb_ast_call_node *call = call_node(varnode);
+ mid = call->method_name;
+ args = call->args;
+ receiver = call->receiver;
+ safe = call->safe_call;
+ }
+ else {
+ codegen_error(s, "unsupported call type in assignment");
+ return;
+ }
+
+ /* Convert method name to assignment form (e.g., [] -> []=) */
+ mrb_sym assign_mid = attrsym(s, mid);
+
+ /* Check for optimizable operations */
+ if (!noop) {
+ if (mid == MRB_OPSYM(aref)) opt_op = OP_SETIDX;
+ }
+
+ top = cursp();
+ if (val || sp == cursp()) {
+ push(); /* room for retval */
+ }
+ callsp = cursp();
+
+ /* Generate receiver */
+ if (!receiver) {
+ noself = 1;
+ push();
+ }
+ else {
+ codegen(s, receiver, VAL); /* receiver */
+ }
+
+ /* Handle safe navigation */
+ if (safe) {
+ int recv = cursp()-1;
+ gen_move(s, cursp(), recv, 1);
+ skip = genjmp2_0(s, OP_JMPNIL, cursp(), val);
+ }
+
+ /* Generate arguments from original call */
+ if (args) {
+ struct mrb_ast_callargs *callargs = (struct mrb_ast_callargs*)args;
+ if (callargs->regular_args) {
+ node *regular_args = callargs->regular_args;
+ node *arg_iter = regular_args;
+ while (arg_iter) {
+ codegen(s, arg_iter->car, VAL);
+ n++;
+ arg_iter = arg_iter->cdr;
+ }
+ if (n > 13) { /* leave room for rhs */
+ pop_n(n);
+ genop_2(s, OP_ARRAY, cursp(), n);
+ push();
+ n = 15;
+ noop = 1;
+ }
}
- break;
- case NODE_IF:
- {
- uint32_t pos1, pos2;
- mrb_bool nil_p = FALSE;
- node *elsepart = tree->cdr->cdr->car;
-
- if (!tree->car) {
- codegen(s, elsepart, val);
- goto exit;
- }
- if (true_always(tree->car)) {
- codegen(s, tree->cdr->car, val);
- goto exit;
- }
- if (false_always(tree->car)) {
- codegen(s, elsepart, val);
- goto exit;
- }
- if (nint(tree->car->car) == NODE_CALL) {
- node *n = tree->car->cdr;
- mrb_sym mid = nsym(n->cdr->car);
- mrb_sym sym_nil_p = MRB_SYM_Q_2(s->mrb, nil);
- if (mid == sym_nil_p && n->cdr->cdr->car == NULL) {
- nil_p = TRUE;
- codegen(s, n->car, VAL);
- }
+ /* Handle keyword arguments if present */
+ if (callargs->keyword_args) {
+ node *kwargs = callargs->keyword_args;
+ if (n == 13 || n == 14) {
+ pop_n(n);
+ genop_2(s, OP_ARRAY, cursp(), n);
+ push();
+ n = 15;
}
- if (!nil_p) {
- codegen(s, tree->car, VAL);
+ gen_hash(s, kwargs->cdr, VAL, 0);
+ if (n < 14) {
+ n++;
}
- pop();
- if (val || tree->cdr->car) {
- if (nil_p) {
- pos2 = genjmp2_0(s, OP_JMPNIL, cursp(), val);
- pos1 = genjmp_0(s, OP_JMP);
- dispatch(s, pos2);
- }
- else {
- pos1 = genjmp2_0(s, OP_JMPNOT, cursp(), val);
- }
- codegen(s, tree->cdr->car, val);
- if (val) pop();
- if (elsepart || val) {
- pos2 = genjmp_0(s, OP_JMP);
- dispatch(s, pos1);
- codegen(s, elsepart, val);
- dispatch(s, pos2);
+ else {
+ pop_n(2);
+ genop_2(s, OP_ARYPUSH, cursp(), 1);
+ }
+ push();
+ noop = 1;
+ }
+ }
+
+ /* Generate rhs (the assigned value) */
+ if (rhs) {
+ codegen(s, rhs, VAL);
+ pop();
+ }
+ else {
+ /* For compound assignments, move the computed value from sp to cursp() */
+ gen_move(s, cursp(), sp, 0);
+ }
+ if (val) {
+ gen_move(s, top, cursp(), 1);
+ }
+ /* Account for the value being assigned (either from rhs or already on stack) */
+ if (n < 14) {
+ n++;
+ }
+ else {
+ if (rhs) {
+ pop_n(2);
+ genop_2(s, OP_ARYPUSH, cursp(), 1);
+ push();
+ }
+ }
+
+ /* Generate the optimized instruction or method call */
+ push(); push();
+ s->sp = callsp;
+
+ if (opt_op == OP_SETIDX && n == 2) {
+ /* Always preserve return value for SETIDX - assignments return the assigned value */
+ genop_1(s, OP_SETIDX, cursp());
+ }
+ else if (noself) {
+ genop_3(s, OP_SSEND, cursp(), sym_idx(s, assign_mid), n|(nk<<4));
+ }
+ else {
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, assign_mid), n|(nk<<4));
+ }
+
+ if (safe) {
+ dispatch(s, skip);
+ }
+
+ /* Restore stack pointer like legacy code */
+ s->sp = top;
+
+ if (val) {
+ push();
+ }
+}
+
+static void
+codegen_array(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_array_node *array = array_node(varnode);
+ node *elements = array->elements;
+ int regular_elements = 0;
+ int first = 1;
+ int slimit = GEN_LIT_ARY_MAX;
+
+ if (!val) return;
+
+ if (!elements) {
+ genop_2(s, OP_ARRAY, cursp(), 0);
+ push();
+ return;
+ }
+
+ if (cursp() >= slimit) slimit = GEN_VAL_STACK_MAX;
+
+ /* Process each element using cons-list iteration, handling splats */
+ node *current = elements;
+ while (current) {
+ struct mrb_ast_node *element = current->car;
+ int is_splat = is_splat_node(element);
+
+ /* Skip splat of an empty literal array: [*[]] => [] without ARYCAT noise */
+ if (is_splat) {
+ struct mrb_ast_splat_node *splat = splat_node(element);
+ node *sv = splat->value;
+ if (sv) {
+ enum node_type nt = node_type(sv);
+ if (nt == NODE_ARRAY) {
+ struct mrb_ast_array_node *an = array_node(sv);
+ if (an->elements == NULL) {
+ current = current->cdr;
+ continue;
+ }
}
- else {
- dispatch(s, pos1);
+ else if (nt == NODE_ZARRAY) {
+ current = current->cdr;
+ continue;
}
}
- else { /* empty then-part */
- if (elsepart) {
- if (nil_p) {
- pos1 = genjmp2_0(s, OP_JMPNIL, cursp(), val);
- }
- else {
- pos1 = genjmp2_0(s, OP_JMPIF, cursp(), val);
- }
- codegen(s, elsepart, val);
- dispatch(s, pos1);
+ }
+
+ if (is_splat || cursp() >= slimit) { /* flush accumulated elements */
+ if (regular_elements > 0) {
+ pop_n(regular_elements);
+ if (first) {
+ genop_2(s, OP_ARRAY, cursp(), regular_elements);
+ push();
+ first = 0;
}
- else if (val && !nil_p) {
- genop_1(s, OP_LOADNIL, cursp());
+ else {
+ pop();
+ genop_2(s, OP_ARYPUSH, cursp(), regular_elements);
push();
}
+ regular_elements = 0;
+ }
+ else if (first && is_splat) {
+ /* First element is splat - create empty array */
+ genop_1(s, OP_LOADNIL, cursp());
+ genop_2(s, OP_ARRAY, cursp(), 0);
+ push();
+ first = 0;
}
}
- break;
- case NODE_AND:
- {
- uint32_t pos;
+ codegen(s, element, val);
- if (true_always(tree->car)) {
- codegen(s, tree->cdr, val);
- goto exit;
- }
- if (false_always(tree->car)) {
- codegen(s, tree->car, val);
- goto exit;
- }
- codegen(s, tree->car, VAL);
- pop();
- pos = genjmp2_0(s, OP_JMPNOT, cursp(), val);
- codegen(s, tree->cdr, val);
- dispatch(s, pos);
+ if (is_splat) {
+ /* Concatenate splat array */
+ pop(); pop();
+ genop_1(s, OP_ARYCAT, cursp());
+ push();
+ }
+ else {
+ regular_elements++;
}
- break;
- case NODE_OR:
- {
- uint32_t pos;
+ current = current->cdr;
+ }
- if (true_always(tree->car)) {
- codegen(s, tree->car, val);
- goto exit;
- }
- if (false_always(tree->car)) {
- codegen(s, tree->cdr, val);
- goto exit;
- }
- codegen(s, tree->car, VAL);
- pop();
- pos = genjmp2_0(s, OP_JMPIF, cursp(), val);
- codegen(s, tree->cdr, val);
- dispatch(s, pos);
+ /* Handle any remaining regular elements */
+ if (!first) {
+ /* Variable length - we have an array from splats */
+ if (regular_elements > 0) {
+ pop_n(regular_elements + 1);
+ genop_2(s, OP_ARYPUSH, cursp(), regular_elements);
+ push();
}
- break;
+ }
+ else {
+ /* Simple case: no splats, just create array */
+ pop_n(regular_elements);
+ genop_2(s, OP_ARRAY, cursp(), regular_elements);
+ push();
+ }
+}
- case NODE_WHILE:
- case NODE_UNTIL:
- {
- if (true_always(tree->car)) {
- if (nt == NODE_UNTIL) {
- if (val) {
- genop_1(s, OP_LOADNIL, cursp());
- push();
- }
- goto exit;
- }
- }
- else if (false_always(tree->car)) {
- if (nt == NODE_WHILE) {
- if (val) {
- genop_1(s, OP_LOADNIL, cursp());
- push();
- }
- goto exit;
- }
- }
+/* Control flow and definition node codegen functions */
+static mrb_bool
+callargs_empty(node *n)
+{
+ if (!n) return TRUE;
+ return (callargs_node(n)->regular_args == 0 && callargs_node(n)->keyword_args == 0 && callargs_node(n)->block_arg == 0);
+}
- uint32_t pos = JMPLINK_START;
- struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
+static void
+codegen_if(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_if_node *if_n = if_node(varnode);
+ node *condition = if_n->condition;
+ node *then_body = if_n->then_body;
+ node *else_body = if_n->else_body;
+ uint32_t pos1, pos2;
+ mrb_bool nil_p = FALSE;
+
+ if (!condition) {
+ codegen(s, else_body, val);
+ return;
+ }
+ if (true_always(condition)) {
+ codegen(s, then_body, val);
+ return;
+ }
+ if (false_always(condition)) {
+ codegen(s, else_body, val);
+ return;
+ }
- if (!val) lp->reg = -1;
- lp->pc0 = new_label(s);
- codegen(s, tree->car, VAL);
- pop();
- if (nt == NODE_WHILE) {
- pos = genjmp2_0(s, OP_JMPNOT, cursp(), NOVAL);
+ /* Check for nil? optimization */
+ if (node_type(condition) == NODE_CALL) {
+ /* Variable-sized NODE_CALL */
+ struct mrb_ast_call_node *call_n = (struct mrb_ast_call_node*)condition;
+ mrb_sym sym_nil_p = MRB_SYM_Q(nil);
+ if (call_n->method_name == sym_nil_p && callargs_empty(call_n->args)) {
+ nil_p = TRUE;
+ codegen(s, call_n->receiver, VAL);
+ }
+ }
+
+ if (!nil_p) {
+ /* Generate condition code */
+ codegen(s, condition, VAL);
+ }
+ pop();
+
+ if (val || then_body) {
+ if (nil_p) {
+ pos2 = genjmp2_0(s, OP_JMPNIL, cursp(), val);
+ pos1 = genjmp_0(s, OP_JMP);
+ dispatch(s, pos2);
+ }
+ else {
+ pos1 = genjmp2_0(s, OP_JMPNOT, cursp(), val);
+ }
+ codegen(s, then_body, val);
+ if (val) pop();
+ if (else_body || val) {
+ pos2 = genjmp_0(s, OP_JMP);
+ dispatch(s, pos1);
+ codegen(s, else_body, val);
+ dispatch(s, pos2);
+ }
+ else {
+ dispatch(s, pos1);
+ }
+ }
+ else { /* empty then-part */
+ if (else_body) {
+ if (nil_p) {
+ pos1 = genjmp2_0(s, OP_JMPNIL, cursp(), val);
}
else {
- pos = genjmp2_0(s, OP_JMPIF, cursp(), NOVAL);
+ pos1 = genjmp2_0(s, OP_JMPIF, cursp(), val);
}
- lp->pc1 = new_label(s);
- genop_0(s, OP_NOP); /* for redo */
- codegen(s, tree->cdr, NOVAL);
- genjmp(s, OP_JMP, lp->pc0);
- dispatch(s, pos);
- loop_pop(s, val);
+ codegen(s, else_body, val);
+ dispatch(s, pos1);
}
- break;
+ else if (val && !nil_p) {
+ gen_load_nil(s, 1);
+ }
+ }
+}
- case NODE_FOR:
- for_body(s, tree);
+static void
+codegen_while(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_while_node *while_n = while_node(varnode);
+ node *condition = while_n->condition;
+ node *body = while_n->body;
+
+ /* Check for constant conditions first */
+ if (true_always(condition)) {
+ /* while true - infinite loop, don't generate condition check */
+ struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
+ if (!val) lp->reg = -1;
+ lp->pc0 = new_label(s);
+ lp->pc1 = new_label(s);
+ genop_0(s, OP_NOP); /* for redo */
+ codegen(s, body, NOVAL);
+ genjmp(s, OP_JMP, lp->pc0);
+ loop_pop(s, val);
+ return;
+ }
+ if (false_always(condition)) {
+ /* while false - never execute, just return nil */
+ if (val) {
+ gen_load_nil(s, 1);
+ }
+ return;
+ }
+
+ struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
+ uint32_t pos;
+
+ if (!val) lp->reg = -1;
+ lp->pc0 = new_label(s);
+ codegen(s, condition, VAL);
+ pop();
+ pos = genjmp2_0(s, OP_JMPNOT, cursp(), NOVAL);
+ lp->pc1 = new_label(s);
+ genop_0(s, OP_NOP); /* for redo */
+ codegen(s, body, NOVAL);
+ genjmp(s, OP_JMP, lp->pc0);
+ dispatch(s, pos);
+ loop_pop(s, val);
+}
+
+static void
+codegen_until(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_until_node *until_n = until_node(varnode);
+ node *condition = until_n->condition;
+ node *body = until_n->body;
+
+ /* Check for constant conditions first */
+ if (true_always(condition)) {
+ /* until true - never execute, just return nil */
+ if (val) {
+ gen_load_nil(s, 1);
+ }
+ return;
+ }
+ if (false_always(condition)) {
+ /* until false - infinite loop, don't generate condition check */
+ struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
+ if (!val) lp->reg = -1;
+ lp->pc0 = new_label(s);
+ lp->pc1 = new_label(s);
+ genop_0(s, OP_NOP); /* for redo */
+ codegen(s, body, NOVAL);
+ genjmp(s, OP_JMP, lp->pc0);
+ loop_pop(s, val);
+ return;
+ }
+
+ struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
+ uint32_t pos;
+
+ if (!val) lp->reg = -1;
+ lp->pc0 = new_label(s);
+ codegen(s, condition, VAL);
+ pop();
+ pos = genjmp2_0(s, OP_JMPIF, cursp(), NOVAL);
+ lp->pc1 = new_label(s);
+ genop_0(s, OP_NOP); /* for redo */
+ codegen(s, body, NOVAL);
+ genjmp(s, OP_JMP, lp->pc0);
+ dispatch(s, pos);
+ loop_pop(s, val);
+}
+
+static void
+codegen_while_mod(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_while_node *while_n = while_node(varnode);
+ node *condition = while_n->condition;
+ node *body = while_n->body;
+
+ /* Handle special constant cases for post-tested loops */
+ if (false_always(condition)) {
+ /* begin...end while false - execute once then exit */
+ codegen(s, body, val);
if (val) push();
- break;
+ return;
+ }
+ if (true_always(condition)) {
+ /* begin...end while true - infinite loop after first execution */
+ struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
+ if (!val) lp->reg = -1;
- case NODE_CASE:
- {
- int head = 0;
- uint32_t pos1, pos2, pos3, tmp;
- node *n;
-
- pos3 = JMPLINK_START;
- if (tree->car) {
- head = cursp();
- codegen(s, tree->car, VAL);
- }
- tree = tree->cdr;
- while (tree) {
- n = tree->car->car;
- pos1 = pos2 = JMPLINK_START;
- while (n) {
- codegen(s, n->car, VAL);
- if (head) {
- gen_move(s, cursp(), head, 0);
- push(); push(); pop(); pop(); pop();
- if (nint(n->car->car) == NODE_SPLAT) {
- genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, __case_eqq)), 1);
- }
- else {
- genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_OPSYM_2(s->mrb, eqq)), 1);
- }
- }
- else {
- pop();
- }
- tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, !head);
- pos2 = tmp;
- n = n->cdr;
+ uint32_t pos0 = genjmp_0(s, OP_JMP);
+ lp->pc0 = new_label(s);
+ lp->pc1 = new_label(s);
+ genop_0(s, OP_NOP); /* for redo */
+ dispatch(s, pos0);
+ codegen(s, body, NOVAL);
+ genjmp(s, OP_JMP, lp->pc0);
+ loop_pop(s, val);
+ return;
+ }
+
+ /* Normal post-tested while loop */
+ struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
+ if (!val) lp->reg = -1;
+
+ uint32_t pos0 = genjmp_0(s, OP_JMP);
+ lp->pc0 = new_label(s);
+ codegen(s, condition, VAL);
+ pop();
+ uint32_t pos = genjmp2_0(s, OP_JMPNOT, cursp(), NOVAL);
+ lp->pc1 = new_label(s);
+ genop_0(s, OP_NOP); /* for redo */
+ dispatch(s, pos0);
+ codegen(s, body, NOVAL);
+ genjmp(s, OP_JMP, lp->pc0);
+ dispatch(s, pos);
+ loop_pop(s, val);
+}
+
+static void
+codegen_until_mod(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_until_node *until_n = until_node(varnode);
+ node *condition = until_n->condition;
+ node *body = until_n->body;
+
+ /* Handle special constant cases for post-tested loops */
+ if (true_always(condition)) {
+ /* begin...end until true - execute once then exit */
+ codegen(s, body, val);
+ if (val) push();
+ return;
+ }
+ if (false_always(condition)) {
+ /* begin...end until false - infinite loop after first execution */
+ struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
+ if (!val) lp->reg = -1;
+
+ uint32_t pos0 = genjmp_0(s, OP_JMP);
+ lp->pc0 = new_label(s);
+ lp->pc1 = new_label(s);
+ genop_0(s, OP_NOP); /* for redo */
+ dispatch(s, pos0);
+ codegen(s, body, NOVAL);
+ genjmp(s, OP_JMP, lp->pc0);
+ loop_pop(s, val);
+ return;
+ }
+
+ /* Normal post-tested until loop */
+ struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
+ if (!val) lp->reg = -1;
+
+ uint32_t pos0 = genjmp_0(s, OP_JMP);
+ lp->pc0 = new_label(s);
+ codegen(s, condition, VAL);
+ pop();
+ uint32_t pos = genjmp2_0(s, OP_JMPIF, cursp(), NOVAL);
+ lp->pc1 = new_label(s);
+ genop_0(s, OP_NOP); /* for redo */
+ dispatch(s, pos0);
+ codegen(s, body, NOVAL);
+ genjmp(s, OP_JMP, lp->pc0);
+ dispatch(s, pos);
+ loop_pop(s, val);
+}
+
+static void
+codegen_for(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_for_node *for_n = for_node(varnode);
+ node *var = for_n->var;
+ node *iterable = for_n->iterable;
+ node *body = for_n->body;
+
+ codegen_scope *prev = s;
+ int idx;
+ struct loopinfo *lp;
+
+ /* generate receiver */
+ codegen(s, iterable, VAL);
+ /* generate loop-block */
+ s = scope_new(s->mrb, s, NULL);
+
+ push(); /* push for a block parameter */
+
+ /* generate loop variable */
+ genop_W(s, OP_ENTER, 0x40000);
+ if (var->car && !var->car->cdr && !var->cdr) {
+ gen_assignment(s, var->car->car, NULL, 1, NOVAL);
+ }
+ else {
+ gen_massignment(s, var, 1, VAL);
+ }
+ /* construct loop */
+ lp = loop_push(s, LOOP_FOR);
+ lp->pc1 = new_label(s);
+ genop_0(s, OP_NOP); /* for redo */
+
+ /* loop body */
+ codegen(s, body, VAL);
+ pop();
+ gen_return(s, OP_RETURN, cursp());
+ loop_pop(s, NOVAL);
+ scope_finish(s);
+ s = prev;
+ genop_2(s, OP_BLOCK, cursp(), s->irep->rlen-1);
+ push();pop(); /* space for a block */
+ pop();
+ idx = sym_idx(s, MRB_SYM(each));
+ genop_3(s, OP_SENDB, cursp(), idx, 0);
+ if (val) push();
+}
+
+static void
+codegen_case(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_case_node *case_n = case_node(varnode);
+ node *value = case_n->value;
+ node *body = case_n->body;
+
+ int head = 0;
+ uint32_t case_end_jumps, tmp;
+ uint32_t next_when_pos = JMPLINK_START;
+ node *n;
+
+ case_end_jumps = JMPLINK_START;
+
+ /* Handle case value exactly like original */
+ if (value) {
+ head = cursp();
+ codegen(s, value, VAL);
+ }
+
+ /* Iterate through when clauses list with JMPNOT optimization */
+ node *current_when = body;
+ while (current_when) {
+ node *when_clause = current_when->car;
+
+ /* Dispatch previous when's "next" jump to this location */
+ if (next_when_pos != JMPLINK_START) {
+ dispatch_linked(s, next_when_pos);
+ next_when_pos = JMPLINK_START;
+ }
+
+ /* when_clause is (condition . body) cons node */
+ node *args = when_clause->car; /* when conditions */
+ node *when_body = when_clause->cdr; /* when body */
+
+ /* Process when conditions with JMPNOT optimization */
+ n = args;
+ uint32_t condition_success_pos = JMPLINK_START;
+
+ while (n) {
+ codegen(s, n->car, VAL);
+ if (head) {
+ gen_move(s, cursp(), head, 0);
+ push(); push(); pop(); pop(); pop();
+ if (is_splat_node(n->car)) {
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_SYM(__case_eqq)), 1);
}
- if (tree->car->car) {
- pos1 = genjmp_0(s, OP_JMP);
- dispatch_linked(s, pos2);
+ else {
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(eqq)), 1);
}
- codegen(s, tree->car->cdr, val);
- if (val) pop();
- tmp = genjmp(s, OP_JMP, pos3);
- pos3 = tmp;
- dispatch(s, pos1);
- tree = tree->cdr;
}
- if (val) {
- uint32_t pos = cursp();
- genop_1(s, OP_LOADNIL, cursp());
- if (pos3 != JMPLINK_START) dispatch_linked(s, pos3);
- if (head) pop();
- if (cursp() != pos) {
- gen_move(s, cursp(), pos, 0);
- }
- push();
+ else {
+ pop();
+ }
+
+ if (n->cdr) {
+ /* More conditions in this when - use JMPIF to success handler */
+ tmp = genjmp2(s, OP_JMPIF, cursp(), condition_success_pos, !head);
+ condition_success_pos = tmp;
}
else {
- if (pos3 != JMPLINK_START) {
- dispatch_linked(s, pos3);
- }
- if (head) {
- pop();
- }
+ /* Last condition - use JMPNOT to next when clause */
+ tmp = genjmp2(s, OP_JMPNOT, cursp(), next_when_pos, !head);
+ next_when_pos = tmp;
}
+ n = n->cdr;
}
- break;
- case NODE_SCOPE:
- scope_body(s, tree, NOVAL);
- break;
+ /* Dispatch multiple condition success jumps to body */
+ if (condition_success_pos != JMPLINK_START) {
+ dispatch_linked(s, condition_success_pos);
+ }
- case NODE_CALL:
- case NODE_FCALL:
- gen_call(s, tree, val, 0);
- break;
- case NODE_SCALL:
- gen_call(s, tree, val, 1);
- break;
+ /* Generate when body */
+ codegen(s, when_body, val);
+ if (val) pop();
- case NODE_DOT2:
- codegen(s, tree->car, val);
- codegen(s, tree->cdr, val);
+ /* Check if this is the last when clause before else, or if there's no else clause */
+ node *next_node = current_when->cdr;
+
+ tmp = genjmp(s, OP_JMP, case_end_jumps);
+ case_end_jumps = tmp;
+
+ current_when = next_node;
+ }
+
+ /* Handle case where no else clause was found */
+ if (next_when_pos != JMPLINK_START) {
+ dispatch_linked(s, next_when_pos);
+ /* No else clause, generate LOADNIL for VAL case */
if (val) {
- pop(); pop();
- genop_1(s, OP_RANGE_INC, cursp());
- push();
+ genop_1(s, OP_LOADNIL, cursp());
}
- break;
+ }
- case NODE_DOT3:
- codegen(s, tree->car, val);
- codegen(s, tree->cdr, val);
- if (val) {
- pop(); pop();
- genop_1(s, OP_RANGE_EXC, cursp());
- push();
+ /* Apply stack management strategy for cases without else clause */
+ if (val) {
+ /* Dispatch remaining case_end_jumps */
+ if (case_end_jumps != JMPLINK_START) {
+ dispatch_linked(s, case_end_jumps);
}
- break;
+ if (head) {
+ /* Move result to original case value position */
+ gen_move(s, head, cursp(), 0);
+ pop();
+ }
+ /* Always push to maintain stack alignment */
+ push();
+ }
+ else {
+ /* NOVAL case */
+ if (case_end_jumps != JMPLINK_START) {
+ dispatch_linked(s, case_end_jumps);
+ }
+ if (head) {
+ pop();
+ }
+ }
+}
- case NODE_COLON2:
- {
- int sym = new_sym(s, nsym(tree->cdr));
+/* Forward declaration for pattern matching code generation
+ * known_array_len: -1 if unknown, >= 0 if target is known to be an array of that length
+ */
+static void codegen_pattern(codegen_scope *s, node *pattern, int target, uint32_t *fail_pos, int known_array_len);
- codegen(s, tree->car, VAL);
- pop();
- genop_2(s, OP_GETMCNST, cursp(), sym);
- if (val) push();
+/* Pattern matching case/in expression */
+static void
+codegen_case_match(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_case_match_node *case_match_n = case_match_node(varnode);
+ node *value = case_match_n->value;
+ node *in_clauses = case_match_n->in_clauses;
+
+ int head = cursp();
+ uint32_t case_end_jumps = JMPLINK_START;
+ uint32_t tmp;
+
+ /* Check if value is an array literal - allows optimizations in pattern matching */
+ int known_array_len = -1;
+ if (node_type(value) == NODE_ARRAY) {
+ struct mrb_ast_array_node *arr = array_node(value);
+ node *elem;
+ known_array_len = 0;
+ for (elem = arr->elements; elem; elem = elem->cdr) known_array_len++;
+ }
+
+ /* Generate code for the case value */
+ codegen(s, value, VAL);
+
+ /* Iterate through in clauses */
+ node *current_in = in_clauses;
+ while (current_in) {
+ struct mrb_ast_in_node *in_n = in_node(current_in->car);
+ node *pattern = in_n->pattern;
+ node *guard = in_n->guard;
+ mrb_bool guard_is_unless = in_n->guard_is_unless;
+ node *body = in_n->body;
+
+ uint32_t fail_pos = JMPLINK_START;
+
+ if (pattern) {
+ /* Generate pattern matching code */
+ codegen_pattern(s, pattern, head, &fail_pos, known_array_len);
+ }
+
+ /* Generate guard clause if present */
+ if (guard) {
+ codegen(s, guard, VAL);
+ pop(); /* pop before jump - cursp() now points to guard result */
+ if (guard_is_unless) {
+ /* unless guard: fail if guard is true */
+ tmp = genjmp2(s, OP_JMPIF, cursp(), fail_pos, 0);
+ }
+ else {
+ /* if guard: fail if guard is false */
+ tmp = genjmp2(s, OP_JMPNOT, cursp(), fail_pos, 0);
+ }
+ fail_pos = tmp;
}
- break;
- case NODE_COLON3:
- {
- int sym = new_sym(s, nsym(tree));
+ /* Generate in-clause body */
+ codegen(s, body, val);
+ if (val) pop();
+
+ /* Jump to end of case/in */
+ tmp = genjmp(s, OP_JMP, case_end_jumps);
+ case_end_jumps = tmp;
- genop_1(s, OP_OCLASS, cursp());
- genop_2(s, OP_GETMCNST, cursp(), sym);
- if (val) push();
+ /* Dispatch fail jumps to next in-clause */
+ if (fail_pos != JMPLINK_START) {
+ dispatch_linked(s, fail_pos);
}
- break;
- case NODE_ARRAY:
+ current_in = current_in->cdr;
+ }
+
+ /* No pattern matched - raise NoMatchingPatternError */
+ genop_1(s, OP_LOADFALSE, cursp());
+ genop_1(s, OP_MATCHERR, cursp());
+
+ /* Dispatch all end jumps */
+ if (case_end_jumps != JMPLINK_START) {
+ dispatch_linked(s, case_end_jumps);
+ }
+
+ if (val) {
+ /* Move result to original case value position */
+ gen_move(s, head, cursp(), 0);
+ pop();
+ push();
+ }
+ else {
+ pop(); /* pop the case value */
+ }
+}
+
+/* Generate pattern matching code for a single pattern.
+ * target: stack position of the value being matched
+ * fail_pos: linked list of jump positions for pattern match failure
+ * known_array_len: -1 if unknown, >= 0 if target is known to be an array of that length
+ */
+/* generate code to load a hash pattern key onto the stack */
+static void
+gen_pat_key(codegen_scope *s, node *key)
+{
+ if (node_type(key) == NODE_SYM) {
+ genop_2(s, OP_LOADSYM, cursp(), sym_idx(s, sym_node(key)->symbol));
+ }
+ else {
+ codegen(s, key, VAL);
+ }
+}
+
+/* generate OP_ARRAY of hash pattern keys on the stack */
+static void
+gen_pat_keys_ary(codegen_scope *s, node *pairs, int num_keys)
+{
+ int i = 0;
+ node *pair;
+ for (pair = pairs; pair; pair = pair->cdr, i++) {
+ gen_pat_key(s, pair->car->car);
+ push();
+ }
+ genop_2(s, OP_ARRAY, cursp() - num_keys, num_keys);
+ for (i = 1; i < num_keys; i++) pop();
+}
+
+static void
+codegen_pattern(codegen_scope *s, node *pattern, int target, uint32_t *fail_pos, int known_array_len)
+{
+ uint32_t tmp;
+
+ switch (node_type(pattern)) {
+ case NODE_PAT_VALUE:
{
- int n;
+ struct mrb_ast_pat_value_node *pat_val = pat_value_node(pattern);
+ /* Generate: pattern_value === target */
+ codegen(s, pat_val->value, VAL);
+ gen_move(s, cursp(), target, 0);
+ push(); push(); pop(); pop(); pop();
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(eqq)), 1);
+ /* Jump to fail if not matched */
+ tmp = genjmp2(s, OP_JMPNOT, cursp(), *fail_pos, 1);
+ *fail_pos = tmp;
+ }
+ break;
- n = gen_values(s, tree, val, 0);
- if (val) {
- if (n >= 0) {
- pop_n(n);
- genop_2(s, OP_ARRAY, cursp(), n);
+ case NODE_PAT_VAR:
+ {
+ struct mrb_ast_pat_var_node *pat_var = pat_var_node(pattern);
+ if (pat_var->name) {
+ /* Bind the matched value to the variable */
+ int idx = lv_idx(s, pat_var->name);
+ if (idx > 0) {
+ gen_move(s, idx, target, 1); /* nopeep=1 to prevent optimization */
}
- push();
}
+ /* Variable pattern always matches (wildcard if name is 0) */
}
break;
- case NODE_HASH:
- case NODE_KW_HASH:
+ case NODE_PAT_ALT:
{
- int nk = gen_hash(s, tree, val, GEN_LIT_ARY_MAX);
- if (val && nk >= 0) {
- pop_n(nk*2);
- genop_2(s, OP_HASH, cursp(), nk);
- push();
+ struct mrb_ast_pat_alt_node *pat_alt = pat_alt_node(pattern);
+ uint32_t left_fail = JMPLINK_START;
+ uint32_t success_pos = JMPLINK_START;
+
+ /* Try left pattern */
+ codegen_pattern(s, pat_alt->left, target, &left_fail, known_array_len);
+
+ /* Optimize JMPNOT+JMP to JMPIF when:
+ * 1. Left pattern is not another NODE_PAT_ALT (avoid recursion issues)
+ * 2. Left pattern generated at least one JMPNOT
+ * 3. The last JMPNOT is immediately before current position
+ * 4. The instruction is actually OP_JMPNOT (not OP_JMP which has
+ * different format S vs BS - converting OP_JMP would corrupt bytecode)
+ * In this case, convert JMPNOT to JMPIF and skip generating JMP */
+ if (node_type(pat_alt->left) != NODE_PAT_ALT &&
+ left_fail != JMPLINK_START && left_fail + 2 == s->pc &&
+ s->iseq[left_fail - 2] == OP_JMPNOT) {
+ /* Extract the previous link from the JMPNOT chain.
+ * The chain uses relative offsets where the end is marked by
+ * an offset that points to address 0 (i.e., (pos+2)+offset == 0) */
+ int16_t prev_offset = (int16_t)PEEK_S(s->iseq + left_fail);
+ int32_t next_addr = (int32_t)(left_fail + 2) + prev_offset;
+ uint32_t prev_link = (next_addr == 0) ? JMPLINK_START : (uint32_t)next_addr;
+ /* Convert JMPNOT to JMPIF */
+ s->iseq[left_fail - 2] = OP_JMPIF;
+ /* Clear offset to mark end of success chain */
+ emit_S(s, left_fail, 0);
+ success_pos = left_fail;
+ /* Continue with remaining fail chain */
+ left_fail = prev_link;
+ }
+ else {
+ /* Left succeeded - jump to success */
+ tmp = genjmp(s, OP_JMP, success_pos);
+ success_pos = tmp;
+ }
+
+ /* Left failed - try right pattern */
+ if (left_fail != JMPLINK_START) {
+ dispatch_linked(s, left_fail);
+ }
+ codegen_pattern(s, pat_alt->right, target, fail_pos, known_array_len);
+
+ /* Dispatch success jumps */
+ if (success_pos != JMPLINK_START) {
+ dispatch_linked(s, success_pos);
}
}
break;
- case NODE_SPLAT:
- codegen(s, tree, val);
+ case NODE_PAT_AS:
+ {
+ struct mrb_ast_pat_as_node *pat_as = pat_as_node(pattern);
+ /* First match the pattern */
+ codegen_pattern(s, pat_as->pattern, target, fail_pos, known_array_len);
+ /* Then bind the value to the variable */
+ int idx = lv_idx(s, pat_as->name);
+ if (idx > 0) {
+ gen_move(s, idx, target, 0);
+ }
+ }
break;
- case NODE_ASGN:
- gen_assignment(s, tree->car, tree->cdr, 0, val);
+ case NODE_PAT_PIN:
+ {
+ struct mrb_ast_pat_pin_node *pat_pin = pat_pin_node(pattern);
+ /* Get the current value of the pinned variable */
+ int idx = lv_idx(s, pat_pin->name);
+ if (idx > 0) {
+ /* Compare: pinned_value === target */
+ gen_move(s, cursp(), idx, 0); /* Load pinned variable */
+ push();
+ gen_move(s, cursp(), target, 0); /* Load target */
+ push(); push(); pop(); pop(); pop();
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(eqq)), 1);
+ /* Jump to fail if not matched */
+ tmp = genjmp2(s, OP_JMPNOT, cursp(), *fail_pos, 1);
+ *fail_pos = tmp;
+ }
+ else {
+ /* Variable not found - raise compile error like CRuby */
+ codegen_error(s, "no such local variable for pin operator");
+ }
+ }
break;
- case NODE_MASGN:
+ case NODE_PAT_ARRAY:
{
- int len = 0, n = 0, post = 0;
- node *t = tree->cdr, *p;
- int rhs = cursp();
-
- if (!val && nint(t->car) == NODE_ARRAY && t->cdr && nosplat(t->cdr)) {
- /* fixed rhs */
- t = t->cdr;
- while (t) {
- codegen(s, t->car, VAL);
- len++;
- t = t->cdr;
- }
- tree = tree->car;
- if (tree->car) { /* pre */
- t = tree->car;
- n = 0;
- while (t) {
- if (n < len) {
- gen_assignment(s, t->car, NULL, rhs+n, NOVAL);
- n++;
- }
- else {
- genop_1(s, OP_LOADNIL, rhs+n);
- gen_assignment(s, t->car, NULL, rhs+n, NOVAL);
- }
- t = t->cdr;
+ struct mrb_ast_pat_array_node *pat_arr = pat_array_node(pattern);
+ int pre_len = 0, post_len = 0;
+ int arr_reg;
+ node *elem;
+ int i;
+
+ /* Count pre and post elements */
+ for (elem = pat_arr->pre; elem; elem = elem->cdr) pre_len++;
+ for (elem = pat_arr->post; elem; elem = elem->cdr) post_len++;
+
+ /* Optimization: if we know the target is an array, skip deconstruct */
+ if (known_array_len >= 0) {
+ /* Use target directly as array register */
+ arr_reg = target;
+ /* Compile-time size check */
+ if (pat_arr->rest == 0) {
+ /* No rest: exact length match required */
+ if (known_array_len != pre_len) {
+ /* Size mismatch - always fail */
+ tmp = genjmp(s, OP_JMP, *fail_pos);
+ *fail_pos = tmp;
+ break;
}
+ /* Size matches, no runtime check needed */
}
- t = tree->cdr;
- if (t) {
- if (t->cdr) { /* post count */
- p = t->cdr->car;
- while (p) {
- post++;
- p = p->cdr;
- }
+ else {
+ /* Has rest: minimum length check */
+ int min_len = pre_len + post_len;
+ if (known_array_len < min_len) {
+ /* Size too small - always fail */
+ tmp = genjmp(s, OP_JMP, *fail_pos);
+ *fail_pos = tmp;
+ break;
}
- if (t->car) { /* rest (len - pre - post) */
- int rn;
+ /* Size sufficient, no runtime check needed */
+ }
- if (len < post + n) {
- rn = 0;
- }
- else {
- rn = len - post - n;
- }
- if (cursp() == rhs+n) {
- genop_2(s, OP_ARRAY, cursp(), rn);
+ /* Match pre-rest elements using GETIDX (faster than SEND :[]) */
+ i = 0;
+ for (elem = pat_arr->pre; elem; elem = elem->cdr, i++) {
+ /* Get arr[i] using GETIDX */
+ gen_move(s, cursp(), arr_reg, 0);
+ push();
+ gen_int(s, cursp(), i);
+ genop_1(s, OP_GETIDX, cursp() - 1); /* R[cursp-1] = R[cursp-1][R[cursp]] */
+ /* Element is now at cursp-1 */
+ /* Match element pattern (elements are not known arrays) */
+ codegen_pattern(s, elem->car, cursp() - 1, fail_pos, -1);
+ pop(); /* Clean up element slot */
+ }
+
+ /* Bind rest elements if rest is a variable */
+ if (pat_arr->rest && pat_arr->rest != (node*)-1) {
+ struct mrb_ast_pat_var_node *rest_var = pat_var_node(pat_arr->rest);
+ if (rest_var->name) {
+ int var_idx = lv_idx(s, rest_var->name);
+ /* Generate: arr[pre_len..-(post_len+1)] or arr[pre_len..-1] if no post */
+ gen_move(s, cursp(), arr_reg, 0); /* arr at cursp */
+ push();
+ gen_int(s, cursp(), pre_len); /* start at cursp */
+ push();
+ if (post_len > 0) {
+ gen_int(s, cursp(), -(post_len + 1)); /* end at cursp */
}
else {
- genop_3(s, OP_ARRAY2, cursp(), rhs+n, rn);
+ gen_int(s, cursp(), -1); /* end at cursp */
}
- gen_assignment(s, t->car, NULL, cursp(), NOVAL);
- n += rn;
- }
- if (t->cdr && t->cdr->car) {
- t = t->cdr->car;
- while (t) {
- if (n<len) {
- gen_assignment(s, t->car, NULL, rhs+n, NOVAL);
- }
- else {
- genop_1(s, OP_LOADNIL, cursp());
- gen_assignment(s, t->car, NULL, cursp(), NOVAL);
- }
- t = t->cdr;
- n++;
+ /* start at cursp-1, end at cursp; create inclusive range at cursp-1 */
+ genop_1(s, OP_RANGE_INC, cursp() - 1);
+ /* arr at cursp-2, range at cursp-1 */
+ pop(); /* cursp now at range position */
+ pop(); /* cursp now at arr position */
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(aref)), 1);
+ if (var_idx > 0) {
+ gen_move(s, var_idx, cursp(), 1);
}
}
}
- pop_n(len);
- }
- else {
- /* variable rhs */
- codegen(s, t, VAL);
- gen_massignment(s, tree->car, rhs, val);
- if (!val) {
- pop();
- }
- }
- }
- break;
- case NODE_OP_ASGN:
- {
- mrb_sym sym = nsym(tree->cdr->car);
- mrb_int len;
- const char *name = mrb_sym_name_len(s->mrb, sym, &len);
- int idx, callargs = -1, vsp = -1;
-
- if ((len == 2 && name[0] == '|' && name[1] == '|') &&
- (nint(tree->car->car) == NODE_CONST ||
- nint(tree->car->car) == NODE_CVAR)) {
- int catch_entry, begin, end;
- int noexc, exc;
- struct loopinfo *lp;
-
- lp = loop_push(s, LOOP_BEGIN);
- lp->pc0 = new_label(s);
- catch_entry = catch_handler_new(s);
- begin = s->pc;
- exc = cursp();
- codegen(s, tree->car, VAL);
- end = s->pc;
- noexc = genjmp_0(s, OP_JMP);
- lp->type = LOOP_RESCUE;
- catch_handler_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc);
- genop_1(s, OP_EXCEPT, exc);
- genop_1(s, OP_LOADF, exc);
- dispatch(s, noexc);
- loop_pop(s, NOVAL);
- }
- else if (nint(tree->car->car) == NODE_CALL) {
- node *n = tree->car->cdr;
- int base, i, nargs = 0;
- callargs = 0;
-
- if (val) {
- vsp = cursp();
+ /* Match post-rest elements using GETIDX */
+ i = -post_len;
+ for (elem = pat_arr->post; elem; elem = elem->cdr, i++) {
+ /* Get arr[i] using GETIDX (negative index from end) */
+ gen_move(s, cursp(), arr_reg, 0);
push();
+ gen_int(s, cursp(), i);
+ genop_1(s, OP_GETIDX, cursp() - 1);
+ /* Match element pattern */
+ codegen_pattern(s, elem->car, cursp() - 1, fail_pos, -1);
+ pop(); /* Clean up element slot */
}
- codegen(s, n->car, VAL); /* receiver */
- idx = new_sym(s, nsym(n->cdr->car));
- base = cursp()-1;
- if (n->cdr->cdr->car) {
- nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 13);
- if (nargs >= 0) {
- callargs = nargs;
- }
- else { /* varargs */
- push();
- nargs = 1;
- callargs = CALL_MAXARGS;
- }
- }
- /* copy receiver and arguments */
- gen_move(s, cursp(), base, 1);
- for (i=0; i<nargs; i++) {
- gen_move(s, cursp()+i+1, base+i+1, 1);
- }
- push_n(nargs+2);pop_n(nargs+2); /* space for receiver, arguments and a block */
- genop_3(s, OP_SEND, cursp(), idx, callargs);
- push();
+ /* No arr_reg to pop since we used target directly */
}
else {
- codegen(s, tree->car, VAL);
- }
- if (len == 2 &&
- ((name[0] == '|' && name[1] == '|') ||
- (name[0] == '&' && name[1] == '&'))) {
- uint32_t pos;
+ /* General case: need to call deconstruct and check size at runtime */
+ arr_reg = cursp();
- pop();
- if (val) {
- if (vsp >= 0) {
- gen_move(s, vsp, cursp(), 1);
- }
- pos = genjmp2_0(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), val);
+ /* Call deconstruct on target */
+ gen_move(s, cursp(), target, 0);
+ push();
+ genop_3(s, OP_SEND, arr_reg, sym_idx(s, MRB_SYM(deconstruct)), 0);
+
+ /* Check length constraints */
+ if (pat_arr->rest == 0) {
+ /* No rest: exact length match */
+ /* Generate: arr.size == pre_len using EQ opcode */
+ gen_move(s, cursp(), arr_reg, 0);
+ push();
+ genop_3(s, OP_SEND, cursp() - 1, sym_idx(s, MRB_SYM(size)), 0);
+ gen_int(s, cursp(), pre_len);
+ /* EQ: R[a] = R[a] == R[a+1]; size at cursp-1, pre_len at cursp */
+ genop_1(s, OP_EQ, cursp() - 1);
+ tmp = genjmp2(s, OP_JMPNOT, cursp() - 1, *fail_pos, 1);
+ *fail_pos = tmp;
+ pop();
}
else {
- pos = genjmp2_0(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), val);
- }
- codegen(s, tree->cdr->cdr->car, VAL);
- pop();
- if (val && vsp >= 0) {
- gen_move(s, vsp, cursp(), 1);
- }
- if (nint(tree->car->car) == NODE_CALL) {
- if (callargs == CALL_MAXARGS) {
+ /* Has rest: minimum length check */
+ int min_len = pre_len + post_len;
+ if (min_len > 0) {
+ /* Generate: arr.size >= min_len using GE opcode */
+ gen_move(s, cursp(), arr_reg, 0);
+ push();
+ genop_3(s, OP_SEND, cursp() - 1, sym_idx(s, MRB_SYM(size)), 0);
+ gen_int(s, cursp(), min_len);
+ /* GE: R[a] = R[a] >= R[a+1]; size at cursp-1, min_len at cursp */
+ genop_1(s, OP_GE, cursp() - 1);
+ tmp = genjmp2(s, OP_JMPNOT, cursp() - 1, *fail_pos, 1);
+ *fail_pos = tmp;
pop();
- genop_2(s, OP_ARYPUSH, cursp(), 1);
- }
- else {
- pop_n(callargs);
- callargs++;
}
- pop();
- idx = new_sym(s, attrsym(s, nsym(tree->car->cdr->cdr->car)));
- genop_3(s, OP_SEND, cursp(), idx, callargs);
}
- else {
- gen_assignment(s, tree->car, NULL, cursp(), val);
- }
- dispatch(s, pos);
- goto exit;
- }
- codegen(s, tree->cdr->cdr->car, VAL);
- push(); pop();
- pop(); pop();
- if (len == 1 && name[0] == '+') {
- gen_addsub(s, OP_ADD, cursp());
- }
- else if (len == 1 && name[0] == '-') {
- gen_addsub(s, OP_SUB, cursp());
- }
- else if (len == 1 && name[0] == '*') {
- genop_1(s, OP_MUL, cursp());
- }
- else if (len == 1 && name[0] == '/') {
- genop_1(s, OP_DIV, cursp());
- }
- else if (len == 1 && name[0] == '<') {
- genop_1(s, OP_LT, cursp());
- }
- else if (len == 2 && name[0] == '<' && name[1] == '=') {
- genop_1(s, OP_LE, cursp());
- }
- else if (len == 1 && name[0] == '>') {
- genop_1(s, OP_GT, cursp());
- }
- else if (len == 2 && name[0] == '>' && name[1] == '=') {
- genop_1(s, OP_GE, cursp());
- }
- else {
- idx = new_sym(s, sym);
- genop_3(s, OP_SEND, cursp(), idx, 1);
- }
- if (callargs < 0) {
- gen_assignment(s, tree->car, NULL, cursp(), val);
- }
- else {
- if (val && vsp >= 0) {
- gen_move(s, vsp, cursp(), 0);
+ /* Match pre-rest elements */
+ i = 0;
+ for (elem = pat_arr->pre; elem; elem = elem->cdr, i++) {
+ /* Get arr[i] */
+ gen_move(s, cursp(), arr_reg, 0);
+ push();
+ gen_int(s, cursp(), i);
+ push(); push(); pop(); pop(); pop();
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(aref)), 1);
+ push(); /* Preserve element result for codegen_pattern */
+ /* Match element pattern */
+ codegen_pattern(s, elem->car, cursp() - 1, fail_pos, -1);
+ pop(); /* Clean up element slot */
}
- if (callargs == CALL_MAXARGS) {
- pop();
- genop_2(s, OP_ARYPUSH, cursp(), 1);
+
+ /* Bind rest elements if rest is a variable */
+ if (pat_arr->rest && pat_arr->rest != (node*)-1) {
+ struct mrb_ast_pat_var_node *rest_var = pat_var_node(pat_arr->rest);
+ if (rest_var->name) {
+ int var_idx = lv_idx(s, rest_var->name);
+ /* Generate: arr[pre_len..-(post_len+1)] or arr[pre_len..-1] if no post */
+ gen_move(s, cursp(), arr_reg, 0); /* arr at cursp */
+ push();
+ gen_int(s, cursp(), pre_len); /* start at cursp */
+ push();
+ if (post_len > 0) {
+ gen_int(s, cursp(), -(post_len + 1)); /* end at cursp */
+ }
+ else {
+ gen_int(s, cursp(), -1); /* end at cursp */
+ }
+ /* start at cursp-1, end at cursp; create inclusive range at cursp-1 */
+ genop_1(s, OP_RANGE_INC, cursp() - 1);
+ /* arr at cursp-2, range at cursp-1 */
+ pop(); /* cursp now at range position */
+ pop(); /* cursp now at arr position */
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(aref)), 1);
+ if (var_idx > 0) {
+ gen_move(s, var_idx, cursp(), 1);
+ }
+ }
}
- else {
- pop_n(callargs);
- callargs++;
+
+ /* Match post-rest elements */
+ i = -post_len;
+ for (elem = pat_arr->post; elem; elem = elem->cdr, i++) {
+ /* Get arr[i] (negative index from end) */
+ gen_move(s, cursp(), arr_reg, 0);
+ push();
+ gen_int(s, cursp(), i);
+ push(); push(); pop(); pop(); pop();
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(aref)), 1);
+ push(); /* Preserve element result for codegen_pattern */
+ /* Match element pattern */
+ codegen_pattern(s, elem->car, cursp() - 1, fail_pos, -1);
+ pop(); /* Clean up element slot */
}
- pop();
- idx = new_sym(s, attrsym(s,nsym(tree->car->cdr->cdr->car)));
- genop_3(s, OP_SEND, cursp(), idx, callargs);
+
+ pop(); /* Pop arr_reg */
}
}
break;
- case NODE_SUPER:
+ case NODE_PAT_FIND:
{
- codegen_scope *s2 = s;
- int lv = 0;
- int n = 0, nk = 0, st = 0;
+ /* Find pattern: [*pre, elem1, elem2, ..., *post]
+ * Searches for elems anywhere in the array.
+ *
+ * Stack layout:
+ * arr_reg: deconstructed array (stable)
+ * idx_reg: current search index (stable)
+ *
+ * Loop bound is recomputed each iteration since OP_SEND clobbers registers.
+ */
+ struct mrb_ast_pat_find_node *pat_find = pat_find_node(pattern);
+ int elems_len = 0;
+ node *elem;
+ int arr_reg = cursp();
+ int idx_reg;
+ uint32_t loop_start, match_fail, loop_end;
+
+ /* Count middle elements */
+ for (elem = pat_find->elems; elem; elem = elem->cdr) elems_len++;
+
+ /* Call deconstruct on target */
+ gen_move(s, cursp(), target, 0);
+ push();
+ genop_3(s, OP_SEND, arr_reg, sym_idx(s, MRB_SYM(deconstruct)), 0);
+ /* Check minimum length: arr.size >= elems_len */
+ gen_move(s, cursp(), arr_reg, 0);
push();
- while (!s2->mscope) {
- lv++;
- s2 = s2->prev;
- if (!s2) break;
- }
- if (tree) {
- node *args = tree->car;
- if (args) {
- st = n = gen_values(s, args, VAL, 14);
- if (n < 0) {
- st = 1; n = 15;
- push();
- }
- }
- /* keyword arguments */
- if (tree->cdr->car) {
- nk = gen_hash(s, tree->cdr->car->cdr, VAL, 14);
- if (nk < 0) {st++; nk = 15;}
- else st += nk*2;
- n |= nk<<4;
- }
- /* block arguments */
- if (tree->cdr->cdr) {
- codegen(s, tree->cdr->cdr, VAL);
+ genop_3(s, OP_SEND, cursp() - 1, sym_idx(s, MRB_SYM(size)), 0);
+ gen_int(s, cursp(), elems_len);
+ push(); push(); pop(); pop(); pop();
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(ge)), 1);
+ tmp = genjmp2(s, OP_JMPNOT, cursp(), *fail_pos, 1);
+ *fail_pos = tmp;
+
+ /* Initialize index to 0 */
+ idx_reg = cursp();
+ gen_int(s, idx_reg, 0);
+ push();
+
+ /* Loop: try matching at each position */
+ loop_start = s->pc;
+ match_fail = JMPLINK_START;
+
+ /* Check if idx <= arr.size - elems_len (i.e., idx < arr.size - elems_len + 1) */
+ /* Compute: arr.size - elems_len */
+ gen_move(s, cursp(), arr_reg, 0);
+ push();
+ genop_3(s, OP_SEND, cursp() - 1, sym_idx(s, MRB_SYM(size)), 0);
+ gen_int(s, cursp(), elems_len);
+ push(); push(); pop(); pop(); pop();
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(sub)), 1);
+ /* Now cursp() has (size - elems_len), compare: idx <= (size - elems_len) */
+ gen_move(s, cursp() + 1, idx_reg, 0);
+ push();
+ push(); push(); pop(); pop(); pop();
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(ge)), 1);
+ tmp = genjmp2(s, OP_JMPNOT, cursp(), *fail_pos, 1);
+ *fail_pos = tmp;
+
+ /* Try to match each middle element at idx+offset */
+ int offset = 0;
+ for (elem = pat_find->elems; elem; elem = elem->cdr, offset++) {
+ /* Get arr[idx + offset] */
+ gen_move(s, cursp(), arr_reg, 0);
+ push();
+ if (offset == 0) {
+ gen_move(s, cursp(), idx_reg, 0);
}
- else if (s2) gen_blkmove(s, s2->ainfo, lv);
else {
- genop_1(s, OP_LOADNIL, cursp());
+ gen_move(s, cursp(), idx_reg, 0);
+ push();
+ gen_int(s, cursp(), offset);
+ push(); push(); pop(); pop(); pop();
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(add)), 1);
+ }
+ push(); push(); pop(); pop(); pop();
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(aref)), 1);
+ push(); /* Preserve element result for codegen_pattern */
+ /* Match element pattern - on fail, try next index */
+ codegen_pattern(s, elem->car, cursp() - 1, &match_fail, -1);
+ pop(); /* Clean up element slot */
+ }
+
+ /* All elements matched - bind pre and post if named */
+ if (pat_find->pre && pat_find->pre != (node*)-1) {
+ struct mrb_ast_pat_var_node *pre_var = pat_var_node(pat_find->pre);
+ if (pre_var->name) {
+ int var_idx = lv_idx(s, pre_var->name);
+ /* pre = arr[0...idx] (exclusive range) */
+ /* Following the NODE_PAT_ARRAY pattern exactly */
+ gen_move(s, cursp(), arr_reg, 0); /* arr at cursp */
push();
+ gen_int(s, cursp(), 0); /* start=0 at cursp */
+ push();
+ gen_move(s, cursp(), idx_reg, 0); /* end=idx at cursp */
+ /* start at cursp-1, end at cursp; create exclusive range at cursp-1 */
+ genop_1(s, OP_RANGE_EXC, cursp() - 1);
+ /* arr at cursp-2, range at cursp-1 */
+ pop(); /* cursp now at range position */
+ pop(); /* cursp now at arr position */
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(aref)), 1);
+ if (var_idx > 0) {
+ gen_move(s, var_idx, cursp(), 1);
+ }
}
}
- else {
- if (s2) gen_blkmove(s, s2->ainfo, lv);
- else {
- genop_1(s, OP_LOADNIL, cursp());
+
+ if (pat_find->post && pat_find->post != (node*)-1) {
+ struct mrb_ast_pat_var_node *post_var = pat_var_node(pat_find->post);
+ if (post_var->name) {
+ int var_idx = lv_idx(s, post_var->name);
+ /* post = arr[(idx+elems_len)..-1] (inclusive range) */
+ /* Following the NODE_PAT_ARRAY pattern exactly */
+ gen_move(s, cursp(), arr_reg, 0); /* arr at cursp */
+ push();
+ /* Compute idx + elems_len for start index */
+ gen_move(s, cursp(), idx_reg, 0); /* idx at cursp */
push();
+ gen_int(s, cursp(), elems_len); /* elems_len at cursp */
+ push(); push(); pop(); pop(); pop();
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(add)), 1);
+ /* start index (idx+elems_len) now at cursp */
+ push();
+ gen_int(s, cursp(), -1); /* end=-1 at cursp */
+ /* start at cursp-1, end at cursp; create inclusive range at cursp-1 */
+ genop_1(s, OP_RANGE_INC, cursp() - 1);
+ /* arr at cursp-2, range at cursp-1 */
+ pop(); /* cursp now at range position */
+ pop(); /* cursp now at arr position */
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(aref)), 1);
+ if (var_idx > 0) {
+ gen_move(s, var_idx, cursp(), 1);
+ }
}
}
- st++;
- pop_n(st+1);
- genop_2(s, OP_SUPER, cursp(), n);
- if (val) push();
+
+ /* Jump to success (end of find pattern) */
+ loop_end = genjmp(s, OP_JMP, JMPLINK_START);
+
+ /* Match failed - increment index and try again */
+ dispatch_linked(s, match_fail);
+ gen_move(s, cursp(), idx_reg, 0);
+ push();
+ gen_int(s, cursp(), 1);
+ push(); push(); pop(); pop(); pop();
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(add)), 1);
+ gen_move(s, idx_reg, cursp(), 0);
+ genjmp(s, OP_JMP, loop_start);
+
+ /* Success exit point */
+ dispatch(s, loop_end);
+
+ pop(); /* idx_reg */
+ pop(); /* arr_reg */
}
break;
- case NODE_ZSUPER:
+ case NODE_PAT_HASH:
{
- codegen_scope *s2 = s;
- int lv = 0;
- uint16_t ainfo = 0;
- int n = CALL_MAXARGS;
- int sp = cursp();
+ struct mrb_ast_pat_hash_node *pat_hash = pat_hash_node(pattern);
+ int hash_reg = cursp();
+ node *pair;
+ int num_keys = 0;
+
+ /* Count keys */
+ for (pair = pat_hash->pairs; pair; pair = pair->cdr) num_keys++;
+
+ /* Call deconstruct_keys.
+ * Pass nil when all keys are needed (rest or exact match).
+ * Pass keys array only for partial match (optimization for custom classes). */
+ gen_move(s, cursp(), target, 0);
+ push();
+ if (pat_hash->rest == NULL && num_keys > 0) {
+ /* Partial match: pass keys array */
+ gen_pat_keys_ary(s, pat_hash->pairs, num_keys);
+ }
+ else {
+ genop_1(s, OP_LOADNIL, cursp());
+ push();
+ }
+ genop_3(s, OP_SEND, hash_reg, sym_idx(s, MRB_SYM(deconstruct_keys)), 1);
+ pop();
- push(); /* room for receiver */
- while (!s2->mscope) {
- lv++;
- s2 = s2->prev;
- if (!s2) break;
- }
- if (s2 && s2->ainfo > 0) {
- ainfo = s2->ainfo;
- }
- if (lv > 0xf) codegen_error(s, "too deep nesting");
- if (ainfo > 0) {
- genop_2S(s, OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf));
- push(); push(); push(); /* ARGARY pushes 3 values at most */
- pop(); pop(); pop();
- /* keyword arguments */
- if (ainfo & 0x1) {
- n |= CALL_MAXARGS<<4;
+ /* Check all keys exist and get values via __pat_values */
+ if (num_keys > 0) {
+ int vals_reg = cursp();
+ gen_move(s, vals_reg, hash_reg, 0);
+ push();
+ gen_pat_keys_ary(s, pat_hash->pairs, num_keys);
+ genop_3(s, OP_SEND, vals_reg, sym_idx(s, MRB_SYM(__pat_values)), 1);
+ pop(); /* keys_ary */
+ /* vals_reg = values array or false; fail if false */
+ tmp = genjmp2(s, OP_JMPNOT, vals_reg, *fail_pos, 1);
+ *fail_pos = tmp;
+
+ /* Match each value against its pattern */
+ int i = 0;
+ for (pair = pat_hash->pairs; pair; pair = pair->cdr, i++) {
+ node *pat = pair->car->cdr;
+
+ gen_move(s, cursp(), vals_reg, 0);
push();
- }
- /* block argument */
- if (tree && tree->cdr && tree->cdr->cdr) {
+ gen_int(s, cursp(), i);
+ push(); push(); pop(); pop(); pop();
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_OPSYM(aref)), 1);
push();
- codegen(s, tree->cdr->cdr, VAL);
+
+ codegen_pattern(s, pat, cursp() - 1, fail_pos, -1);
+ pop();
}
+ pop(); /* vals_reg */
}
- else {
- /* block argument */
- if (tree && tree->cdr && tree->cdr->cdr) {
- codegen(s, tree->cdr->cdr, VAL);
- }
- else if (s2) {
- gen_blkmove(s, 0, lv);
- }
- else {
- genop_1(s, OP_LOADNIL, cursp());
+
+ /* Handle rest pattern */
+ if (pat_hash->rest == (node*)-1 || (num_keys == 0 && pat_hash->rest == NULL)) {
+ /* **nil or empty {}: exact match - verify hash.size == num_keys */
+ gen_move(s, cursp(), hash_reg, 0);
+ push();
+ genop_3(s, OP_SEND, cursp() - 1, sym_idx(s, MRB_SYM(size)), 0);
+ gen_int(s, cursp(), num_keys);
+ genop_1(s, OP_EQ, cursp() - 1);
+ tmp = genjmp2(s, OP_JMPNOT, cursp() - 1, *fail_pos, 1);
+ *fail_pos = tmp;
+ pop();
+ }
+ else if (pat_hash->rest && pat_hash->rest != (node*)-2) {
+ /* **var: capture remaining keys via hash.__except(keys_array) */
+ struct mrb_ast_pat_var_node *rest_var = pat_var_node(pat_hash->rest);
+ if (rest_var->name) {
+ int var_idx = lv_idx(s, rest_var->name);
+ int recv = cursp();
+ gen_move(s, recv, hash_reg, 0);
+ push();
+ if (num_keys > 0) {
+ gen_pat_keys_ary(s, pat_hash->pairs, num_keys);
+ genop_3(s, OP_SEND, recv, sym_idx(s, MRB_SYM(__except)), 1);
+ pop();
+ }
+ else {
+ genop_3(s, OP_SEND, recv, sym_idx(s, MRB_SYM(dup)), 0);
+ }
+ if (var_idx > 0) {
+ gen_move(s, var_idx, recv, 1);
+ }
+ pop();
}
- n = 0;
}
- s->sp = sp;
- genop_2(s, OP_SUPER, cursp(), n);
- if (val) push();
+
+ pop(); /* hash_reg */
}
break;
- case NODE_RETURN:
- if (tree) {
- gen_retval(s, tree);
- }
- else {
+ default:
+ raise_error(s, "unsupported pattern type");
+ break;
+ }
+}
+
+/* Definition node codegen functions */
+
+static void
+codegen_def(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_def_node *def_n = def_node(varnode);
+ int sym = sym_idx(s, def_n->name);
+
+ /* Call lambda_body directly with individual parameters */
+ /* For NODE_DEF, args should contain the full locals structure from defn_setup */
+ int idx = lambda_body(s, def_n->locals, def_n->args, def_n->body, 0);
+
+ if (idx <= 0xff) {
+ /* TDEF fusion: TCLASS + METHOD + DEF -> TDEF */
+ genop_3(s, OP_TDEF, cursp(), sym, idx);
+ }
+ else {
+ genop_1(s, OP_TCLASS, cursp());
+ push();
+ genop_2(s, OP_METHOD, cursp(), idx);
+ push(); pop();
+ pop();
+ genop_2(s, OP_DEF, cursp(), sym);
+ }
+ if (val) push();
+}
+
+/* Helper function for generating class/module/singleton class body */
+/* Forward declaration */
+static mrb_bool is_empty_stmts(node *stmt_node);
+
+static void
+gen_class_body(codegen_scope *s, node *body, int val)
+{
+ int idx;
+
+ if (body && body->cdr) {
+ /* Extract locals and body from the cons structure: (locals . body) */
+ node *locals = body->car;
+ node *body_stmts = body->cdr;
+
+ /* Check for empty body case */
+ if (is_empty_stmts(body_stmts)) {
genop_1(s, OP_LOADNIL, cursp());
}
- if (s->loop) {
- gen_return(s, OP_RETURN_BLK, cursp());
- }
else {
- gen_return(s, OP_RETURN, cursp());
+ /* Generate proper scope with locals and body */
+ idx = scope_body(s, locals, body_stmts, val);
+ genop_2(s, OP_EXEC, cursp(), idx);
}
- if (val) push();
- break;
+ }
+ else {
+ /* No body - load nil */
+ genop_1(s, OP_LOADNIL, cursp());
+ }
+}
- case NODE_YIELD:
- {
- codegen_scope *s2 = s;
- int lv = 0, ainfo = -1;
- int n = 0, nk = 0, sendv = 0;
+/* Helper function for generating namespace/parent for class/module */
+static void
+gen_namespace(codegen_scope *s, node *name)
+{
+ if (name->car == (node*)0) {
+ genop_1(s, OP_LOADNIL, cursp());
+ push();
+ }
+ else if (name->car == (node*)1) {
+ genop_1(s, OP_OCLASS, cursp());
+ push();
+ }
+ else {
+ codegen(s, name->car, VAL);
+ }
+}
+
+static void
+codegen_class(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_class_node *class_n = class_node(varnode);
+ node *name = class_n->name;
+ node *superclass = class_n->superclass;
+ node *body = class_n->body;
+ int idx;
+
+ /* Handle class namespace */
+ gen_namespace(s, name);
+
+ /* Handle superclass */
+ if (superclass) {
+ codegen(s, superclass, VAL);
+ }
+ else {
+ genop_1(s, OP_LOADNIL, cursp());
+ push();
+ }
+
+ pop(); pop();
+
+ /* Create class with name symbol */
+ idx = sym_idx(s, node_to_sym(name->cdr));
+ genop_2(s, OP_CLASS, cursp(), idx);
+
+ /* Generate class body */
+ gen_class_body(s, body, val);
+
+ if (val) {
+ push();
+ }
+}
+
+static void
+codegen_module(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_module_node *module_n = module_node(varnode);
+ node *name = module_n->name;
+ node *body = module_n->body;
+ int idx;
+
+ /* Handle module namespace */
+ gen_namespace(s, name);
+ pop();
+
+ /* Create module with name symbol */
+ idx = sym_idx(s, node_to_sym(name->cdr));
+ genop_2(s, OP_MODULE, cursp(), idx);
+
+ /* Generate module body */
+ gen_class_body(s, body, val);
+
+ if (val) {
+ push();
+ }
+}
- while (!s2->mscope) {
- lv++;
- s2 = s2->prev;
- if (!s2) break;
+static void
+codegen_sclass(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_sclass_node *sclass_n = sclass_node(varnode);
+ node *obj = sclass_n->obj;
+ node *body = sclass_n->body;
+
+ /* Generate code for the singleton object */
+ codegen(s, obj, VAL);
+ pop();
+
+ /* Enter singleton class scope */
+ genop_1(s, OP_SCLASS, cursp());
+
+ /* Generate singleton class body */
+ gen_class_body(s, body, val);
+
+ if (val) {
+ push();
+ }
+}
+
+/* Variable-sized assignment codegen functions */
+static void
+codegen_asgn(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_asgn_node *asgn_n = asgn_node(varnode);
+ node *lhs = asgn_n->lhs;
+ node *rhs = asgn_n->rhs;
+
+ gen_assignment(s, lhs, rhs, 0, val);
+}
+
+static void
+codegen_masgn(codegen_scope *s, node *varnode, node *rhs, int sp, int val)
+{
+ struct mrb_ast_masgn_node *masgn_n = (struct mrb_ast_masgn_node*)varnode;
+
+ /* If called from codegen_variable_node context, use the embedded rhs */
+ if (!rhs && sp == 0) {
+ rhs = masgn_n->rhs;
+ sp = 0; /* Use register 0 as base for standalone assignment */
+ }
+
+ int len = 0, n = 0, post = 0;
+ node *t = rhs ? rhs : masgn_n->rhs, *p;
+ int rhs_reg = sp;
+
+ if (!val && t && node_type(t) == NODE_ARRAY) {
+ struct mrb_ast_array_node *an = array_node(t);
+ if (an->elements && nosplat(an->elements)) {
+ /* fixed rhs */
+ t = an->elements;
+
+ /* Optimization: direct generation for simple cases */
+ /* When all lhs are local vars and all rhs are simple literals, */
+ /* generate directly into target registers (no temporaries) */
+ if (masgn_n->pre && !masgn_n->rest && !masgn_n->post) {
+ int regs[16]; /* support up to 16 variables */
+ node *lhs = masgn_n->pre;
+ node *rhs_elem = t;
+ int rhs_count = 0, lhs_count = 0;
+ mrb_bool all_simple = TRUE;
+
+ /* Count lhs variables */
+ while (lhs && lhs_count < 16) {
+ lhs_count++;
+ lhs = lhs->cdr;
+ }
+
+ /* Count and check rhs are all simple literals */
+ while (rhs_elem && rhs_count < 16) {
+ if (!is_simple_literal(rhs_elem->car)) {
+ all_simple = FALSE;
+ break;
+ }
+ rhs_count++;
+ rhs_elem = rhs_elem->cdr;
+ }
+ /* Only apply when lhs and rhs counts match exactly */
+ lhs = masgn_n->pre;
+ if (all_simple && lhs_count > 0 && lhs_count == rhs_count &&
+ all_lvar_pre(s, lhs, regs, lhs_count)) {
+ /* Direct generation: generate literals into target registers */
+ rhs_elem = t;
+ for (int i = 0; i < lhs_count; i++) {
+ gen_literal_to_reg(s, rhs_elem->car, regs[i]);
+ rhs_elem = rhs_elem->cdr;
+ }
+ return;
+ }
}
- if (s2) {
- ainfo = (int)s2->ainfo;
+
+ rhs_reg = cursp(); /* Save register where values will be pushed */
+ while (t) {
+ codegen(s, t->car, VAL);
+ len++;
+ t = t->cdr;
}
- if (ainfo < 0) codegen_error(s, "invalid yield (SyntaxError)");
- if (lv > 0xf) codegen_error(s, "too deep nesting");
- push();
- if (tree) {
- if (tree->car) {
- n = gen_values(s, tree->car, VAL, 14);
- if (n < 0) {
- n = sendv = 1;
- push();
+ if (masgn_n->pre) { /* pre */
+ t = masgn_n->pre;
+ n = 0;
+ while (t) {
+ if (n < len) {
+ gen_assignment(s, t->car, NULL, rhs_reg+n, NOVAL);
+ n++;
}
+ else {
+ genop_1(s, OP_LOADNIL, rhs_reg+n);
+ gen_assignment(s, t->car, NULL, rhs_reg+n, NOVAL);
+ }
+ t = t->cdr;
+ }
+ }
+ /* Count post variables */
+ if (masgn_n->post) {
+ p = masgn_n->post;
+ while (p) {
+ post++;
+ p = p->cdr;
}
+ }
+ /* Handle rest variable */
+ if (masgn_n->rest && (intptr_t)masgn_n->rest != -1) {
+ int rn;
- if (tree->cdr->car) {
- nk = gen_hash(s, tree->cdr->car->cdr, VAL, 14);
- if (nk < 0) {
- nk = 15;
+ if (len < post + n) {
+ rn = 0;
+ }
+ else {
+ rn = len - post - n;
+ }
+ if (cursp() == rhs_reg+n) {
+ genop_2(s, OP_ARRAY, cursp(), rn);
+ }
+ else {
+ genop_3(s, OP_ARRAY2, cursp(), rhs_reg+n, rn);
+ }
+ gen_assignment(s, masgn_n->rest, NULL, cursp(), NOVAL);
+ n += rn;
+ }
+ /* Handle post variables */
+ if (masgn_n->post) {
+ t = masgn_n->post;
+ while (t) {
+ if (n<len) {
+ gen_assignment(s, t->car, NULL, rhs_reg+n, NOVAL);
+ }
+ else {
+ genop_1(s, OP_LOADNIL, cursp());
+ gen_assignment(s, t->car, NULL, cursp(), NOVAL);
}
+ t = t->cdr;
+ n++;
}
}
- push();pop(); /* space for a block */
- pop_n(n + (nk == 15 ? 1 : nk * 2) + 1);
- genop_2S(s, OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf));
- if (sendv) n = CALL_MAXARGS;
- genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, call)), n|(nk<<4));
- if (val) push();
+ pop_n(len);
+ return;
}
- break;
+ }
- case NODE_BREAK:
- loop_break(s, tree);
- if (val) push();
- break;
+ {
+ /* variable rhs - implement gen_massignment logic directly for variable-sized nodes */
- case NODE_NEXT:
- if (!s->loop) {
- raise_error(s, "unexpected next");
+ /* Check if this is parameter destructuring (called from lambda_body) */
+ if (!rhs && sp > 0) {
+ /* Parameter destructuring: value is already in register sp */
+ rhs_reg = sp;
}
- else if (s->loop->type == LOOP_NORMAL) {
- codegen(s, tree, NOVAL);
- genjmp(s, OP_JMPUW, s->loop->pc0);
+ else if (t) {
+ codegen(s, t, VAL);
+ rhs_reg = cursp() - 1; /* rhs is now at cursp()-1 */
}
else {
- if (tree) {
- codegen(s, tree, VAL);
+ /* No rhs and no sp value - should not happen in normal cases */
+ return;
+ }
+
+ /* Handle the lhs structure directly */
+ n = 0;
+ post = 0;
+
+ if (masgn_n->pre) { /* pre */
+ node *pre = masgn_n->pre;
+ n = 0;
+ while (pre) {
+ int sp = cursp();
+ genop_3(s, OP_AREF, sp, rhs_reg, n);
+ push();
+ gen_assignment(s, pre->car, NULL, sp, NOVAL);
pop();
+ n++;
+ pre = pre->cdr;
}
- else {
- genop_1(s, OP_LOADNIL, cursp());
+ }
+
+ /* Count post variables */
+ if (masgn_n->post) {
+ node *p = masgn_n->post;
+ while (p) {
+ post++;
+ p = p->cdr;
}
- gen_return(s, OP_RETURN, cursp());
}
- if (val) push();
- break;
- case NODE_REDO:
- for (const struct loopinfo *lp = s->loop; ; lp = lp->prev) {
- if (!lp) {
- raise_error(s, "unexpected redo");
- break;
+ /* Only generate APOST if there's rest or post variables */
+ if ((masgn_n->rest && (intptr_t)masgn_n->rest != -1) || masgn_n->post) {
+ gen_move(s, cursp(), rhs_reg, val);
+ push_n(post+1);
+ pop_n(post+1);
+ genop_3(s, OP_APOST, cursp(), n, post);
+ int nn = 1;
+ if (masgn_n->rest && (intptr_t)masgn_n->rest != -1) { /* rest */
+ gen_assignment(s, masgn_n->rest, NULL, cursp(), NOVAL);
}
- if (lp->type != LOOP_BEGIN && lp->type != LOOP_RESCUE) {
- genjmp(s, OP_JMPUW, lp->pc1);
- break;
+ if (masgn_n->post) {
+ node *post_part = masgn_n->post;
+ while (post_part) {
+ gen_assignment(s, post_part->car, NULL, cursp()+nn, NOVAL);
+ post_part = post_part->cdr;
+ nn++;
+ }
}
}
- if (val) push();
- break;
- case NODE_RETRY:
- {
- const struct loopinfo *lp = s->loop;
+ if (!val && t) {
+ pop(); /* pop the rhs value */
+ }
+ }
+}
+
+static void
+codegen_op_asgn(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_op_asgn_node *op_asgn_n = op_asgn_node(varnode);
+ node *lhs = op_asgn_n->lhs;
+ node *rhs = op_asgn_n->rhs;
+ mrb_sym sym = op_asgn_n->op;
+ mrb_int len;
+ const char *name = mrb_sym_name_len(s->mrb, sym, &len);
+ int vsp = -1;
+
+ /* Handle ||= and &&= operators */
+ if (len == 2 &&
+ ((name[0] == '|' && name[1] == '|') ||
+ (name[0] == '&' && name[1] == '&'))) {
+ uint32_t pos;
+ enum node_type lhs_type = node_type(lhs);
- while (lp && lp->type != LOOP_RESCUE) {
- lp = lp->prev;
+ /* For ||= on class variables and constants, wrap read in exception handling */
+ if (name[0] == '|' && (lhs_type == NODE_CVAR || lhs_type == NODE_CONST)) {
+ int catch_entry, begin, end;
+ int noexc, exc;
+ struct loopinfo *lp;
+
+ lp = loop_push(s, LOOP_BEGIN);
+ lp->pc0 = new_label(s);
+ catch_entry = catch_handler_new(s);
+ begin = s->pc;
+ exc = cursp();
+ codegen(s, lhs, VAL);
+ end = s->pc;
+ noexc = genjmp_0(s, OP_JMP);
+ lp->type = LOOP_RESCUE;
+ catch_handler_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc);
+ genop_1(s, OP_EXCEPT, exc);
+ genop_1(s, OP_LOADFALSE, exc);
+ dispatch(s, noexc);
+ loop_pop(s, NOVAL);
+ }
+ else {
+ /* Generate code to get current value of LHS */
+ codegen(s, lhs, VAL);
+ }
+
+ pop();
+ if (val) {
+ if (vsp >= 0) {
+ gen_move(s, vsp, cursp(), 1);
}
- if (!lp) {
- raise_error(s, "unexpected retry");
- break;
+ pos = genjmp2_0(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), val);
+ }
+ else {
+ pos = genjmp2_0(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), val);
+ }
+ codegen(s, rhs, VAL);
+ pop();
+ if (val && vsp >= 0) {
+ gen_move(s, vsp, cursp(), 1);
+ }
+ gen_assignment(s, lhs, NULL, cursp(), val);
+ dispatch(s, pos);
+ return;
+ }
+
+ /* For other operators, generate: lhs = lhs op rhs */
+ codegen(s, lhs, VAL);
+ codegen(s, rhs, VAL);
+ push(); pop();
+ pop(); pop();
+
+ /* Apply the operator */
+ if (len == 1 && name[0] == '+') {
+ gen_addsub(s, OP_ADD, cursp());
+ }
+ else if (len == 1 && name[0] == '-') {
+ gen_addsub(s, OP_SUB, cursp());
+ }
+ else if (len == 1 && name[0] == '*') {
+ genop_1(s, OP_MUL, cursp());
+ }
+ else if (len == 1 && name[0] == '/') {
+ genop_1(s, OP_DIV, cursp());
+ }
+ else if (len == 1 && name[0] == '<') {
+ genop_1(s, OP_LT, cursp());
+ }
+ else if (len == 2 && name[0] == '<' && name[1] == '=') {
+ genop_1(s, OP_LE, cursp());
+ }
+ else if (len == 1 && name[0] == '>') {
+ genop_1(s, OP_GT, cursp());
+ }
+ else if (len == 2 && name[0] == '>' && name[1] == '=') {
+ genop_1(s, OP_GE, cursp());
+ }
+ else {
+ int idx = sym_idx(s, sym);
+ genop_3(s, OP_SEND, cursp(), idx, 1);
+ }
+
+ /* Assign the result back to LHS */
+ gen_assignment(s, lhs, NULL, cursp(), val);
+}
+
+/* Variable-sized expression codegen functions */
+static void
+codegen_and(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_and_node *and_n = (struct mrb_ast_and_node*)varnode;
+ node *left = and_n->left;
+ node *right = and_n->right;
+ uint32_t pos;
+
+ if (true_always(left)) {
+ codegen(s, right, val);
+ return;
+ }
+ if (false_always(left)) {
+ codegen(s, left, val);
+ return;
+ }
+ codegen(s, left, VAL);
+ pop();
+ pos = genjmp2_0(s, OP_JMPNOT, cursp(), val);
+ codegen(s, right, val);
+ dispatch(s, pos);
+}
+
+static void
+codegen_or(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_or_node *or_n = (struct mrb_ast_or_node*)varnode;
+ node *left = or_n->left;
+ node *right = or_n->right;
+ uint32_t pos;
+
+ if (true_always(left)) {
+ codegen(s, left, val);
+ return;
+ }
+ if (false_always(left)) {
+ codegen(s, right, val);
+ return;
+ }
+ codegen(s, left, VAL);
+ pop();
+ pos = genjmp2_0(s, OP_JMPIF, cursp(), val);
+ codegen(s, right, val);
+ dispatch(s, pos);
+}
+
+static void
+codegen_return(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_return_node *return_n = return_node(varnode);
+ node *args = return_n->args;
+
+ if (args) {
+ gen_retval(s, args);
+ }
+ else {
+ genop_1(s, OP_LOADNIL, cursp());
+ }
+ if (s->loop) {
+ gen_return(s, OP_RETURN_BLK, cursp());
+ }
+ else {
+ gen_return(s, OP_RETURN, cursp());
+ }
+ if (!val) return;
+ push();
+}
+
+static void
+codegen_yield(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_yield_node *yield_n = yield_node(varnode);
+ node *args = yield_n->args;
+ codegen_scope *s2 = s;
+ int lv = 0, ainfo = -1;
+ int n = 0, nk = 0, sendv = 0;
+
+ while (!s2->mscope) {
+ lv++;
+ s2 = s2->prev;
+ if (!s2) break;
+ }
+ if (s2) {
+ ainfo = (int)s2->ainfo;
+ }
+ if (ainfo < 0) codegen_error(s, "invalid yield (SyntaxError)");
+ if (lv > 0xf) codegen_error(s, "too deep nesting");
+ push();
+ if (args) {
+ struct mrb_ast_callargs *callargs = (struct mrb_ast_callargs*)args;
+ if (callargs->regular_args) {
+ n = gen_values(s, callargs->regular_args, VAL, 14);
+ if (n < 0) {
+ n = sendv = 1;
+ push();
}
- else {
- genjmp(s, OP_JMPUW, lp->pc0);
+ }
+ if (callargs->keyword_args) {
+ nk = gen_hash(s, callargs->keyword_args, VAL, 14);
+ if (nk < 0) {
+ nk = 15;
}
- if (val) push();
}
- break;
+ }
+ push();pop(); /* space for a block */
+ pop_n(n + (nk == 15 ? 1 : nk * 2) + 1);
+ genop_2S(s, OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf));
+ if (sendv) n = CALL_MAXARGS;
+ if (nk == 0 && n < 15) {
+ /* fast path: direct block call without method dispatch */
+ genop_2(s, OP_BLKCALL, cursp(), n);
+ }
+ else {
+ /* fallback: use SEND for keyword args or splat */
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_SYM(call)), n|(nk<<4));
+ }
+ if (val) push();
+}
- case NODE_LVAR:
- if (val) {
- int idx = lv_idx(s, nsym(tree));
+static void
+codegen_super(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_super_node *super_n = super_node(varnode);
+ node *tree = super_n->args;
- if (idx > 0) {
- gen_move(s, cursp(), idx, val);
+ codegen_scope *s2 = s;
+ int lv = 0;
+ int n = 0, nk = 0, st = 0;
+
+ push();
+ while (!s2->mscope) {
+ lv++;
+ s2 = s2->prev;
+ if (!s2) break;
+ }
+ if (tree) {
+ /* Handle callargs structure - direct casting like new_args() */
+ struct mrb_ast_callargs *callargs = (struct mrb_ast_callargs*)tree;
+
+ /* Regular arguments */
+ if (callargs->regular_args) {
+ st = n = gen_values(s, callargs->regular_args, VAL, 14);
+ if (n < 0) {
+ st = 1; n = 15;
+ push();
+ }
+ }
+
+ /* Keyword arguments */
+ if (callargs->keyword_args) {
+ nk = gen_hash(s, callargs->keyword_args, VAL, 14);
+ if (nk < 0) {st++; nk = 15;}
+ else st += nk*2;
+ n |= nk<<4;
+ }
+
+ /* Block arguments */
+ if (callargs->block_arg) {
+ codegen(s, callargs->block_arg, VAL);
}
+ else if (s2) gen_blkmove(s, s2->ainfo, lv);
else {
- gen_getupvar(s, cursp(), nsym(tree));
+ genop_1(s, OP_LOADNIL, cursp());
+ push();
}
+ }
+ else {
+ if (s2) gen_blkmove(s, s2->ainfo, lv);
+ else {
+ genop_1(s, OP_LOADNIL, cursp());
push();
}
- break;
+ }
+ st++;
+ pop_n(st+1);
+ genop_2(s, OP_SUPER, cursp(), n);
+ if (val) push();
+}
- case NODE_NVAR:
- if (val) {
- int idx = nint(tree);
+/* Variable-sized literal node generation functions */
+static void
+codegen_str(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_str_node *str_n = str_node(varnode);
+ node *list = str_n->list;
- gen_move(s, cursp(), idx, val);
+ /* Use common cons list string codegen */
+ gen_string(s, list, val);
+}
+
+static void
+codegen_dot2(codegen_scope *s, node *varnode, int val)
+{
+ node *left = dot2_node(varnode)->left;
+ node *right = dot2_node(varnode)->right;
+
+ codegen(s, left, val);
+ codegen(s, right, val);
+ if (!val) return;
+ pop(); pop();
+ genop_1(s, OP_RANGE_INC, cursp());
+ push();
+}
+
+static void
+codegen_dot3(codegen_scope *s, node *varnode, int val)
+{
+ node *left = dot3_node(varnode)->left;
+ node *right = dot3_node(varnode)->right;
+
+ codegen(s, left, val);
+ codegen(s, right, val);
+ if (!val) return;
+ pop(); pop();
+ genop_1(s, OP_RANGE_EXC, cursp());
+ push();
+}
+
+static void
+codegen_float(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_float_node *float_n = (struct mrb_ast_float_node*)varnode;
+ const char *value = float_n->value;
+ double f;
+
+ mrb_read_float(value, NULL, &f);
+ int off = new_lit_float(s, (mrb_float)f);
+
+ gen_load_op2(s, OP_LOADL, off, val);
+}
+
+/* Variable-sized simple node generation functions */
+static void
+codegen_self(codegen_scope *s, node *varnode, int val)
+{
+ /* Use traditional self codegen logic */
+ gen_load_op1(s, OP_LOADSELF, val);
+}
+
+static void
+codegen_nil(codegen_scope *s, node *varnode, int val)
+{
+ /* Use traditional nil codegen logic */
+ gen_load_op1(s, OP_LOADNIL, val);
+}
+
+static void
+codegen_true(codegen_scope *s, node *varnode, int val)
+{
+ /* Generate OP_LOADTRUE instruction for true literal */
+ gen_load_op1(s, OP_LOADTRUE, val);
+}
+
+static void
+codegen_false(codegen_scope *s, node *varnode, int val)
+{
+ /* Generate OP_LOADFALSE instruction for false literal */
+ gen_load_op1(s, OP_LOADFALSE, val);
+}
+
+static void
+codegen_const(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_const_node *const_n = const_node(varnode);
+ mrb_sym symbol = const_n->symbol;
+
+ int i = sym_idx(s, symbol);
+ genop_2(s, OP_GETCONST, cursp(), i);
+ if (val) push();
+}
+
+static void
+codegen_rescue(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_rescue_node *rescue = rescue_node(varnode);
+ node *body = rescue->body;
+ node *rescue_clauses = rescue->rescue_clauses;
+ node *else_clause = rescue->else_clause;
+
+ int noexc;
+ uint32_t exend, pos1, pos2, tmp;
+ struct loopinfo *lp;
+ int catch_entry, begin, end;
+
+ if (body == NULL) return;
+ lp = loop_push(s, LOOP_BEGIN);
+ lp->pc0 = new_label(s);
+ catch_entry = catch_handler_new(s);
+ begin = s->pc;
+ codegen(s, body, VAL);
+ pop();
+ lp->type = LOOP_RESCUE;
+ end = s->pc;
+ noexc = genjmp_0(s, OP_JMP);
+ catch_handler_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc);
+ exend = JMPLINK_START;
+ pos1 = JMPLINK_START;
+ if (rescue_clauses) {
+ node *n2 = rescue_clauses;
+ int exc = cursp();
+
+ genop_1(s, OP_EXCEPT, exc);
+ push();
+ while (n2) {
+ node *n3 = n2->car;
+ node *n4 = n3->car;
+
+ dispatch(s, pos1);
+ pos2 = JMPLINK_START;
+ do {
+ if (n4 && n4->car && is_splat_node(n4->car)) {
+ codegen(s, n4->car, VAL);
+ gen_move(s, cursp(), exc, 0);
+ push_n(2); pop_n(2); /* space for one arg and a block */
+ pop();
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, MRB_SYM(__case_eqq)), 1);
+ }
+ else {
+ if (n4) {
+ codegen(s, n4->car, VAL);
+ }
+ else {
+ genop_2(s, OP_GETCONST, cursp(), sym_idx(s, MRB_SYM(StandardError)));
+ push();
+ }
+ pop();
+ genop_2(s, OP_RESCUE, exc, cursp());
+ }
+ tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, val);
+ pos2 = tmp;
+ if (n4) {
+ n4 = n4->cdr;
+ }
+ } while (n4);
+ pos1 = genjmp_0(s, OP_JMP);
+ dispatch_linked(s, pos2);
+ pop();
+ if (n3->cdr->car) {
+ gen_assignment(s, n3->cdr->car, NULL, exc, NOVAL);
+ }
+ if (n3->cdr->cdr->car) {
+ codegen(s, n3->cdr->cdr->car, val);
+ if (val) pop();
+ }
+ tmp = genjmp(s, OP_JMP, exend);
+ exend = tmp;
+ n2 = n2->cdr;
push();
}
- break;
+ if (pos1 != JMPLINK_START) {
+ dispatch(s, pos1);
+ genop_1(s, OP_RAISEIF, exc);
+ }
+ }
+ pop();
+ dispatch(s, noexc);
+ if (else_clause) {
+ codegen(s, else_clause, val);
+ }
+ else if (val) {
+ push();
+ }
+ dispatch_linked(s, exend);
+ loop_pop(s, NOVAL);
+}
- case NODE_GVAR:
- {
- int sym = new_sym(s, nsym(tree));
+static void
+codegen_block(codegen_scope *s, node *varnode, int val)
+{
+ if (!val) return;
- genop_2(s, OP_GETGV, cursp(), sym);
- if (val) push();
- }
- break;
+ struct mrb_ast_block_node *n = block_node(varnode);
- case NODE_IVAR:
- {
- int sym = new_sym(s, nsym(tree));
+ /* Call lambda_body directly with individual parameters */
+ int idx = lambda_body(s, n->locals, n->args, n->body, 1);
+ genop_2(s, OP_BLOCK, cursp(), idx);
+ push();
+}
- genop_2(s, OP_GETIV, cursp(), sym);
- if (val) push();
+static void
+codegen_break(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_break_node *n = (struct mrb_ast_break_node*)varnode;
+ loop_break(s, n->value);
+ if (!val) return;
+ push();
+}
+
+static void
+codegen_next(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_next_node *n = (struct mrb_ast_next_node*)varnode;
+ if (!s->loop) {
+ raise_error(s, "unexpected next");
+ }
+ else if (s->loop->type == LOOP_NORMAL) {
+ codegen(s, n->value, NOVAL);
+ genjmp(s, OP_JMPUW, s->loop->pc0);
+ }
+ else {
+ if (n->value) {
+ codegen(s, n->value, VAL);
+ pop();
}
- break;
+ else {
+ genop_1(s, OP_LOADNIL, cursp());
+ }
+ gen_return(s, OP_RETURN, cursp());
+ }
+ if (!val) return;
+ push();
+}
- case NODE_CVAR:
- {
- int sym = new_sym(s, nsym(tree));
+static void
+codegen_redo(codegen_scope *s, node *varnode, int val)
+{
+ for (const struct loopinfo *lp = s->loop; ; lp = lp->prev) {
+ if (!lp) {
+ raise_error(s, "unexpected redo");
+ break;
+ }
+ if (lp->type != LOOP_BEGIN && lp->type != LOOP_RESCUE) {
+ genjmp(s, OP_JMPUW, lp->pc1);
+ break;
+ }
+ }
+ if (!val) return;
+ push();
+}
+
+static void
+codegen_retry(codegen_scope *s, node *varnode, int val)
+{
+ const struct loopinfo *lp = s->loop;
+
+ while (lp && lp->type != LOOP_RESCUE) {
+ lp = lp->prev;
+ }
+ if (!lp) {
+ raise_error(s, "unexpected retry");
+ }
+ else {
+ genjmp(s, OP_JMPUW, lp->pc0);
+ }
+ if (!val) return;
+ push();
+}
+
+static void
+codegen_xstr(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_xstr_node *n = xstr_node(varnode);
+ node *list = n->list;
+ int sym;
+
+ /* Always execute backtick command for side effects, even in NOVAL mode */
+ push();
+ /* Generate string using common function */
+ gen_string(s, list, VAL);
+
+ push(); /* for block */
+ pop_n(3);
+ sym = sym_idx(s, MRB_OPSYM(tick)); /* ` */
+ genop_3(s, OP_SSEND, cursp(), sym, 1);
+
+ if (val) {
+ push(); /* Keep result on stack if needed */
+ }
+ /* If val=0, the result is discarded but the method was still called */
+}
+
+static void
+codegen_regx(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_regx_node *n = regx_node(varnode);
+
+ if (val) {
+ int sym = sym_idx(s, mrb_intern_lit(s->mrb, REGEXP_CLASS));
+ int argc = 1;
+ int off;
+
+ genop_1(s, OP_OCLASS, cursp());
+ genop_2(s, OP_GETMCNST, cursp(), sym);
+ push();
- genop_2(s, OP_GETCV, cursp(), sym);
- if (val) push();
+ /* Generate regex pattern using common cons list function */
+ gen_string(s, n->list, VAL);
+
+ /* Add flags and/or encoding if present */
+ if ((n->flags && *n->flags) || (n->encoding && *n->encoding)) {
+ /* Add flags (or nil if not present but encoding is) */
+ if (n->flags && *n->flags) {
+ off = new_lit_cstr(s, n->flags);
+ genop_2(s, OP_STRING, cursp(), off);
+ }
+ else {
+ genop_1(s, OP_LOADNIL, cursp());
+ }
+ push();
+ argc++;
+
+ /* Add encoding if present */
+ if (n->encoding && *n->encoding) {
+ off = new_lit_cstr(s, n->encoding);
+ genop_2(s, OP_STRING, cursp(), off);
+ push();
+ argc++;
+ }
}
- break;
- case NODE_CONST:
- {
- int sym = new_sym(s, nsym(tree));
+ push(); /* space for a block */
+ pop_n(argc+2);
+ sym = sym_idx(s, MRB_SYM(compile));
+ genop_3(s, OP_SEND, cursp(), sym, argc);
+ push();
+ }
+ else {
+ /* NOVAL case: still need to evaluate expressions for side effects */
+ gen_string(s, n->list, NOVAL);
+ }
+}
+
+static void
+codegen_heredoc(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_heredoc_node *n = heredoc_node(varnode);
+ // Process heredoc doc field as cons list string
+ gen_string(s, n->info.doc, val);
+}
+
+static void
+codegen_dsym(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_str_node *n = dsym_node(varnode);
+ // Generate the list content, then intern to symbol
+ gen_string(s, n->list, val);
+ if (val) {
+ gen_intern(s);
+ }
+}
+
+static void
+codegen_nth_ref(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_nth_ref_node *n = (struct mrb_ast_nth_ref_node*)varnode;
+ mrb_state *mrb = s->mrb;
+ mrb_value str;
+ int sym;
+
+ str = mrb_format(mrb, "$%d", n->nth);
+ sym = sym_idx(s, mrb_intern_str(mrb, str));
+ gen_load_op2(s, OP_GETGV, sym, val);
+}
- genop_2(s, OP_GETCONST, cursp(), sym);
- if (val) push();
+static void
+codegen_back_ref(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_back_ref_node *n = (struct mrb_ast_back_ref_node*)varnode;
+ char buf[] = {'$', (char)n->type};
+ int sym = sym_idx(s, mrb_intern(s->mrb, buf, sizeof(buf)));
+ gen_load_op2(s, OP_GETGV, sym, val);
+}
+
+static void
+codegen_nvar(codegen_scope *s, node *varnode, int val)
+{
+ if (!val) return;
+ struct mrb_ast_nvar_node *n = (struct mrb_ast_nvar_node*)varnode;
+
+ gen_move(s, cursp(), n->num, val);
+ push();
+}
+
+static void
+codegen_dvar(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_dvar_node *n = (struct mrb_ast_dvar_node*)varnode;
+ // DVAR nodes are not currently used in mruby, but provide basic implementation
+ if (val) {
+ gen_lvar(s, n->name, val);
+ }
+}
+
+/* Unary operator codegen functions */
+static void
+codegen_not(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_not_node *n = (struct mrb_ast_not_node*)varnode;
+ // NOT nodes are rarely used - generate method call to !
+ if (val) {
+ codegen(s, n->operand, TRUE);
+ pop();
+ mrb_sym sym = sym_idx(s, mrb_intern_lit(s->mrb, "!"));
+ genop_3(s, OP_SEND, cursp(), sym, 0);
+ push();
+ }
+}
+
+static void
+codegen_negate(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_negate_node *n = (struct mrb_ast_negate_node*)varnode;
+ node *tree = n->operand;
+
+ /* Check if the operand is a variable-sized node */
+ enum node_type vnt = node_type(tree);
+ switch (vnt) {
+#ifndef MRB_NO_FLOAT
+ case NODE_FLOAT:
+ if (val) {
+ struct mrb_ast_float_node *float_n = (struct mrb_ast_float_node*)tree;
+ const char *value = float_n->value;
+ double f;
+
+ mrb_read_float(value, NULL, &f);
+ int off = new_lit_float(s, (mrb_float)-f);
+
+ gen_load_lit(s, off);
}
break;
+#endif
- case NODE_BACK_REF:
+ case NODE_INT:
if (val) {
- char buf[] = {'$', nchar(tree)};
- int sym = new_sym(s, mrb_intern(s->mrb, buf, sizeof(buf)));
-
- genop_2(s, OP_GETGV, cursp(), sym);
+ int32_t value = int_node(tree)->value;
+ if (value == INT32_MIN) {
+ /* -INT32_MIN overflows, use bigint */
+ int off = new_litbint(s, "2147483648", -10);
+ genop_2(s, OP_LOADL, cursp(), off);
+ }
+ else {
+ gen_int(s, cursp(), -value);
+ }
push();
}
break;
- case NODE_NTH_REF:
+ case NODE_BIGINT:
if (val) {
- mrb_state *mrb = s->mrb;
- mrb_value str;
- int sym;
-
- str = mrb_format(mrb, "$%d", nint(tree));
- sym = new_sym(s, mrb_intern_str(mrb, str));
- genop_2(s, OP_GETGV, cursp(), sym);
+ char *str = bigint_node(tree)->string;
+ int base = bigint_node(tree)->base;
+ /* Negate base to indicate negative number */
+ int off = new_litbint(s, str, -base);
+ genop_2(s, OP_LOADL, cursp(), off);
push();
}
break;
- case NODE_ARG:
- /* should not happen */
+ default:
+ codegen(s, tree, VAL);
+ pop();
+ push_n(2);pop_n(2); /* space for receiver&block */
+ mrb_sym minus = MRB_OPSYM(minus);
+ if (!gen_uniop(s, minus, cursp())) {
+ genop_3(s, OP_SEND, cursp(), sym_idx(s, minus), 0);
+ }
+ if (val) push();
break;
+ }
+}
- case NODE_BLOCK_ARG:
- if (!tree) {
- int idx = lv_idx(s, MRB_OPSYM_2(s->mrb, and));
+static void
+codegen_colon2(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_colon2_node *n = (struct mrb_ast_colon2_node*)varnode;
+ // Generate COLON2 (::) access manually
+ int sym = sym_idx(s, n->name);
+ codegen(s, n->base, VAL);
+ pop();
+ genop_2(s, OP_GETMCNST, cursp(), sym);
+ if (val) push();
+}
+
+static void
+codegen_colon3(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_colon3_node *n = (struct mrb_ast_colon3_node*)varnode;
+ int sym = sym_idx(s, n->name);
+ genop_1(s, OP_OCLASS, cursp());
+ genop_2(s, OP_GETMCNST, cursp(), sym);
+ if (val) push();
+}
+
+static void
+codegen_defined(codegen_scope *s, node *varnode, int val)
+{
+ // DEFINED nodes are rarely used - generate basic implementation
+ (void)varnode; // suppress unused warning
+ if (val) {
+ // For now, just return nil (defined? is complex to implement correctly)
+ genop_1(s, OP_LOADNIL, cursp());
+ push();
+ }
+}
+
+static void
+codegen_zsuper(codegen_scope *s, node *varnode, int val)
+{
+ /* NODE_ZSUPER now uses mrb_ast_super_node, which may have args */
+ struct mrb_ast_super_node *zsuper_n = super_node(varnode);
+ node *tree = zsuper_n->args; /* May be NULL or args added by call_with_block */
- if (idx == 0) {
- gen_getupvar(s, cursp(), MRB_OPSYM_2(s->mrb, and));
+ codegen_scope *s2 = s;
+ int lv = 0;
+ uint16_t ainfo = 0;
+ int n = CALL_MAXARGS;
+ int sp = cursp();
+ mrb_bool has_block_arg = FALSE;
+
+ push(); /* room for receiver */
+ int argary_pos = cursp();
+ while (!s2->mscope) {
+ lv++;
+ s2 = s2->prev;
+ if (!s2) break;
+ }
+ if (s2 && s2->ainfo > 0) {
+ ainfo = s2->ainfo;
+ has_block_arg = (ainfo >> 13) & 0x1;
+ }
+ if (lv > 0xf) codegen_error(s, "too deep nesting");
+ if (ainfo > 0) {
+ genop_2S(s, OP_ARGARY, argary_pos, (ainfo<<4)|(lv & 0xf));
+ push(); push(); push(); /* ARGARY pushes 3 values at most */
+ pop(); pop(); pop();
+ /* keyword arguments */
+ if (ainfo & 0x1) {
+ n |= CALL_MAXARGS<<4;
+ push();
+ /* If parent has keywords but no block parameter, ARGARY reads garbage for block */
+ if (!has_block_arg) {
+ genop_1(s, OP_LOADNIL, argary_pos+2);
}
- else {
- gen_move(s, cursp(), idx, val);
+ }
+ /* block argument - tree here is args, so check for block */
+ if (tree) {
+ struct mrb_ast_callargs *callargs = (struct mrb_ast_callargs*)tree;
+ if (callargs->block_arg) {
+ push();
+ codegen(s, callargs->block_arg, VAL);
}
- if (val) push();
+ }
+ }
+ else {
+ /* block argument */
+ if (tree) {
+ struct mrb_ast_callargs *callargs = (struct mrb_ast_callargs*)tree;
+ if (callargs->block_arg) {
+ codegen(s, callargs->block_arg, VAL);
+ }
+ }
+ else if (s2) {
+ gen_blkmove(s, 0, lv);
}
else {
- codegen(s, tree, val);
+ genop_1(s, OP_LOADNIL, cursp());
}
- break;
+ n = 0;
+ }
+ s->sp = sp;
+ genop_2(s, OP_SUPER, cursp(), n);
+ if (val) push();
+}
+
+static void
+codegen_lambda(codegen_scope *s, node *varnode, int val)
+{
+ if (!val) return;
+
+ struct mrb_ast_lambda_node *n = lambda_node(varnode);
+
+ /* Call lambda_body directly with individual parameters */
+ int idx = lambda_body(s, n->locals, n->args, n->body, 1);
+ genop_2(s, OP_LAMBDA, cursp(), idx);
+ push();
+}
+
+static void
+codegen_words(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_words_node *n = words_node(varnode);
+ gen_literal_array(s, n->args, FALSE, val);
+}
+
+static void
+codegen_symbols(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_symbols_node *n = symbols_node(varnode);
+ gen_literal_array(s, n->args, TRUE, val);
+}
+
+static void
+codegen_splat(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_splat_node *n = splat_node(varnode);
+ // Generate code for the splat value directly
+ codegen(s, n->value, val);
+}
+
+static void
+codegen_block_arg(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_block_arg_node *n = block_arg_node(varnode);
+
+ if (!n->value) {
+ int idx = lv_idx(s, MRB_OPSYM(and));
+
+ if (idx == 0) {
+ gen_getupvar(s, cursp(), MRB_OPSYM(and));
+ }
+ else {
+ gen_move(s, cursp(), idx, val);
+ }
+ if (val) push();
+ }
+ else {
+ codegen(s, n->value, val);
+ }
+}
+
+static void
+codegen_scope_node(codegen_scope *s, const node *varnode, int val)
+{
+ struct mrb_ast_scope_node *scope = scope_node(varnode);
+
+ /* Pass locals and body directly to scope_body() */
+ scope_body(s, scope->locals, scope->body, val);
+}
+
+static void
+codegen_begin(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_begin_node *begin = begin_node(varnode);
+ node *body = begin->body;
+
+ codegen(s, body, val);
+}
+
+static void
+codegen_ensure(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_ensure_node *ensure = ensure_node(varnode);
+ node *body = ensure->body;
+ node *ensure_clause = ensure->ensure_clause;
+
+ if (!ensure_clause || !is_empty_stmts(ensure_clause)) {
+ int catch_entry, begin, end, target;
+ int idx;
+
+ catch_entry = catch_handler_new(s);
+ begin = s->pc;
+ codegen(s, body, val);
+ end = target = s->pc;
+ push();
+ idx = cursp();
+ genop_1(s, OP_EXCEPT, idx);
+ push();
+ codegen(s, ensure_clause, NOVAL);
+ pop();
+ genop_1(s, OP_RAISEIF, idx);
+ pop();
+ catch_handler_set(s, catch_entry, MRB_CATCH_ENSURE, begin, end, target);
+ }
+ else { /* empty ensure ignored */
+ codegen(s, body, val);
+ }
+}
+
+static void
+codegen_stmts(codegen_scope *s, node *varnode, int val)
+{
+ struct mrb_ast_stmts_node *stmts = stmts_node(varnode);
+ node *tree = stmts_node(stmts)->stmts;
+
+ if (val && !tree) {
+ gen_load_nil(s, 1);
+ }
+ while (tree) {
+ codegen(s, tree->car, tree->cdr ? NOVAL : val);
+ tree = tree->cdr;
+ }
+}
+
+static mrb_bool
+is_empty_stmts(node *stmt_node)
+{
+ if (!stmt_node) return TRUE;
+
+ if (node_type(stmt_node) == NODE_STMTS) {
+ /* Variable-sized NODE_STMTS with internal cons-list */
+ struct mrb_ast_stmts_node *stmts = (struct mrb_ast_stmts_node*)stmt_node;
+ return stmts->stmts == NULL;
+ }
+
+ return FALSE;
+}
+/* Declaration codegen functions */
+
+static void
+codegen_alias(codegen_scope *s, const node *varnode, int val)
+{
+ struct mrb_ast_alias_node *alias = alias_node(varnode);
+
+ int a = sym_idx(s, alias->new_name);
+ int b = sym_idx(s, alias->old_name);
+
+ genop_2(s, OP_ALIAS, a, b);
+ gen_load_nil(s, val);
+}
+
+static void
+codegen_undef(codegen_scope *s, const node *varnode, int val)
+{
+ struct mrb_ast_undef_node *undef = undef_node(varnode);
+ node *t = undef->syms;
+
+ while (t) {
+ int symbol = sym_idx(s, node_to_sym(t->car));
+ genop_1(s, OP_UNDEF, symbol);
+ t = t->cdr;
+ }
+ gen_load_nil(s, val);
+}
+
+static void
+codegen_sdef(codegen_scope *s, const node *varnode, int val)
+{
+ struct mrb_ast_sdef_node *sdef = sdef_node(varnode);
+ node *recv = sdef->obj;
+ int sym = sym_idx(s, sdef->name);
+
+ /* Call lambda_body directly with individual parameters */
+ /* For NODE_SDEF, args should contain the full locals structure from defs_setup */
+ int idx = lambda_body(s, sdef->locals, sdef->args, sdef->body, 0);
+
+ codegen(s, recv, VAL);
+ pop();
+ if (idx <= 0xff) {
+ /* SDEF fusion: SCLASS + METHOD + DEF -> SDEF */
+ genop_3(s, OP_SDEF, cursp(), sym, idx);
+ }
+ else {
+ genop_1(s, OP_SCLASS, cursp());
+ push();
+ genop_2(s, OP_METHOD, cursp(), idx);
+ push(); pop();
+ pop();
+ genop_2(s, OP_DEF, cursp(), sym);
+ }
+ if (val) push();
+}
+
+
+static void
+codegen(codegen_scope *s, node *tree, int val)
+{
+ int rlev = s->rlev;
+
+ if (!tree) {
+ if (val) {
+ genop_1(s, OP_LOADNIL, cursp());
+ push();
+ }
+ return;
+ }
+
+ s->rlev++;
+ if (s->rlev > MRB_CODEGEN_LEVEL_MAX) {
+ codegen_error(s, "too complex expression");
+ }
+
+ /* Check if this is a variable-sized node */
+ /* For variable-sized nodes, get filename/lineno from the variable node header */
+ struct mrb_ast_var_header *var_head = get_var_header(tree);
+
+ if (s->irep && s->filename_index != var_head->filename_index) {
+ mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index);
+ const char *filename = mrb_sym_name_len(s->mrb, fname, NULL);
+
+ if (filename) {
+ mrb_debug_info_append_file(s->mrb, s->irep->debug_info,
+ filename, s->lines, s->debug_start_pos, s->pc);
+ }
+ s->debug_start_pos = s->pc;
+ s->filename_index = var_head->filename_index;
+ s->filename_sym = mrb_parser_get_filename(s->parser, var_head->filename_index);
+ }
+ s->lineno = var_head->lineno;
+
+ /* Process variable-sized node directly */
+ enum node_type var_type = (enum node_type)var_head->node_type;
+
+ switch (var_type) {
case NODE_INT:
if (val) {
- char *p = (char*)tree->car;
- int base = nint(tree->cdr->car);
- mrb_int i;
- mrb_bool overflow;
-
- i = readint(s, p, base, FALSE, &overflow);
- if (overflow) {
- int off = new_litbint(s, p, base);
- genop_2(s, OP_LOADL, cursp(), off);
- }
- else {
- gen_int(s, cursp(), i);
- }
+ gen_int(s, cursp(), int_node(tree)->value);
push();
}
break;
-#ifndef MRB_NO_FLOAT
- case NODE_FLOAT:
+ case NODE_BIGINT:
if (val) {
- char *p = (char*)tree;
- double f;
- mrb_read_float(p, NULL, &f);
- int off = new_lit_float(s, (mrb_float)f);
-
+ char *str = bigint_node(tree)->string;
+ int base = bigint_node(tree)->base;
+ int off = new_litbint(s, str, base);
genop_2(s, OP_LOADL, cursp(), off);
push();
}
break;
-#endif
- case NODE_NEGATE:
+ case NODE_SYM:
{
- nt = nint(tree->car);
- switch (nt) {
-#ifndef MRB_NO_FLOAT
- case NODE_FLOAT:
- if (val) {
- char *p = (char*)tree->cdr;
- double f;
- mrb_read_float(p, NULL, &f);
- int off = new_lit_float(s, (mrb_float)-f);
+ int i = sym_idx(s, sym_node(tree)->symbol);
+ gen_load_op2(s, OP_LOADSYM, i, val);
+ }
+ break;
- genop_2(s, OP_LOADL, cursp(), off);
- push();
+ case NODE_LVAR:
+ gen_lvar(s, var_node(tree)->symbol, val);
+ break;
+
+ case NODE_GVAR:
+ gen_xvar(s, var_node(tree)->symbol, val, OP_GETGV);
+ break;
+
+ case NODE_IVAR:
+ gen_xvar(s, var_node(tree)->symbol, val, OP_GETIV);
+ break;
+
+ case NODE_CVAR:
+ gen_xvar(s, var_node(tree)->symbol, val, OP_GETCV);
+ break;
+
+ case NODE_CALL:
+ codegen_call(s, tree, val);
+ break;
+
+ case NODE_ARRAY:
+ codegen_array(s, tree, val);
+ break;
+
+ case NODE_HASH:
+ codegen_hash(s, tree, val);
+ break;
+
+ case NODE_IF:
+ codegen_if(s, tree, val);
+ break;
+
+ case NODE_WHILE:
+ codegen_while(s, tree, val);
+ break;
+
+ case NODE_UNTIL:
+ codegen_until(s, tree, val);
+ break;
+
+ case NODE_FOR:
+ codegen_for(s, tree, val);
+ break;
+
+ case NODE_CASE:
+ codegen_case(s, tree, val);
+ break;
+
+ case NODE_CASE_MATCH:
+ codegen_case_match(s, tree, val);
+ break;
+
+ case NODE_MATCH_PAT:
+ {
+ /* One-line pattern matching: expr in pattern / expr => pattern */
+ struct mrb_ast_match_pat_node *mp = match_pat_node(tree);
+ int head;
+ int known_array_len = -1;
+ uint32_t fail_pos = JMPLINK_START;
+
+ /* Optimize: for simple variable pattern, generate value directly into variable */
+ if (node_type(mp->pattern) == NODE_PAT_VAR) {
+ struct mrb_ast_pat_var_node *pat_var = pat_var_node(mp->pattern);
+ if (pat_var->name) {
+ int idx = lv_idx(s, pat_var->name);
+ if (idx > 0) {
+ codegen(s, mp->value, VAL);
+ pop();
+ gen_move(s, idx, cursp(), 0); /* peephole optimizes LOADI+MOVE */
+ goto match_pat_push_result;
+ }
+ }
+ /* Wildcard pattern - just evaluate value for side effects */
+ codegen(s, mp->value, NOVAL);
+ match_pat_push_result:
+ if (val) {
+ /* 'in' pattern returns true, '=>' pattern returns nil */
+ if (mp->raise_on_fail) {
+ gen_load_nil(s, 1);
+ }
+ else {
+ genop_1(s, OP_LOADTRUE, cursp());
+ push();
+ }
}
break;
-#endif
+ }
+
+ /* Optimize: array literal => array pattern with matching sizes */
+ if (node_type(mp->value) == NODE_ARRAY &&
+ node_type(mp->pattern) == NODE_PAT_ARRAY) {
+ struct mrb_ast_array_node *arr = array_node(mp->value);
+ struct mrb_ast_pat_array_node *pat = pat_array_node(mp->pattern);
+ /* Only optimize for exact match (no rest, no post) */
+ if (pat->rest == 0 && pat->post == NULL) {
+ /* Count array elements and pattern pre elements */
+ int arr_len = 0, pat_len = 0;
+ node *e;
+ for (e = arr->elements; e; e = e->cdr) arr_len++;
+ for (e = pat->pre; e; e = e->cdr) pat_len++;
+ if (arr_len == pat_len) {
+ /* Sizes match - skip deconstruct and size check */
+ int arr_reg = cursp();
+ int i = 0;
+ codegen(s, mp->value, VAL); /* Generate array */
+ /* Extract elements directly with GETIDX */
+ for (e = pat->pre; e; e = e->cdr, i++) {
+ gen_move(s, cursp(), arr_reg, 0);
+ push();
+ gen_int(s, cursp(), i);
+ push();
+ genop_1(s, OP_GETIDX, cursp() - 2); /* R[a] = R[a][R[a+1]] */
+ pop();
+ /* Match element pattern (element is now at cursp()-1) */
+ codegen_pattern(s, e->car, cursp() - 1, &fail_pos, -1);
+ pop(); /* clean up array copy slot */
+ }
+ pop(); /* pop array */
+ if (fail_pos != JMPLINK_START) {
+ goto pattern_fail_handling;
+ }
+ /* Pattern always matches - push result if needed */
+ if (val) {
+ if (mp->raise_on_fail) {
+ gen_load_nil(s, 1); /* '=>' pattern returns nil */
+ }
+ else {
+ genop_1(s, OP_LOADTRUE, cursp()); /* 'in' pattern returns true */
+ push();
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ head = cursp();
+
+ /* Check if value is array literal for optimization */
+ if (node_type(mp->value) == NODE_ARRAY) {
+ struct mrb_ast_array_node *arr = array_node(mp->value);
+ node *elem;
+ known_array_len = 0;
+ for (elem = arr->elements; elem; elem = elem->cdr) known_array_len++;
+ }
+
+ /* Evaluate the value */
+ codegen(s, mp->value, VAL);
- case NODE_INT:
+ /* Generate pattern matching code */
+ codegen_pattern(s, mp->pattern, head, &fail_pos, known_array_len);
+
+ pattern_fail_handling:
+ if (fail_pos != JMPLINK_START) {
+ /* Pattern can fail - generate failure handling code */
+ uint32_t match_pos;
+ int saved_sp = cursp(); /* save stack pointer before branching */
+
+ /* Success path: pattern matched */
+ pop(); /* pop the value */
if (val) {
- char *p = (char*)tree->cdr->car;
- int base = nint(tree->cdr->cdr->car);
- mrb_int i;
- mrb_bool overflow;
-
- i = readint(s, p, base, TRUE, &overflow);
- if (overflow) {
- base = -base;
- int off = new_litbint(s, p, base);
- genop_2(s, OP_LOADL, cursp(), off);
+ /* 'in' pattern returns true, '=>' pattern returns nil */
+ if (mp->raise_on_fail) {
+ gen_load_nil(s, 1);
}
else {
- gen_int(s, cursp(), i);
+ genop_1(s, OP_LOADTRUE, cursp());
+ push();
}
- push();
}
- break;
- default:
- codegen(s, tree, VAL);
- pop();
- push_n(2);pop_n(2); /* space for receiver&block */
- mrb_sym minus = MRB_OPSYM_2(s->mrb, minus);
- if (!gen_uniop(s, minus, cursp())) {
- genop_3(s, OP_SEND, cursp(), new_sym(s, minus), 0);
+ /* Optimize: single JMPNOT can be replaced with MATCHERR for raise_on_fail */
+ /* Conditions: (1) single entry in fail_pos chain,
+ * (2) JMPNOT is immediately before current position (no code between), and
+ * (3) the instruction is actually JMPNOT (not JMP from undefined pinned var) */
+ if ((int32_t)(fail_pos + 2) + (int16_t)PEEK_S(s->iseq+fail_pos) == 0 &&
+ fail_pos + 2 == s->pc &&
+ s->iseq[fail_pos - 2] == OP_JMPNOT) {
+ if (mp->raise_on_fail) {
+ /* Replace JMPNOT(BS,4bytes) with MATCHERR(B,2bytes)+NOP+NOP;
+ * keep the same size so that any jump targeting s->pc stays valid */
+ s->iseq[fail_pos - 2] = OP_MATCHERR;
+ /* fail_pos-1 already holds the register operand */
+ s->iseq[fail_pos] = OP_NOP;
+ s->iseq[fail_pos + 1] = OP_NOP;
+ s->sp = saved_sp - 1;
+ if (val) push();
+ break; /* Pattern matching complete */
+ }
+ /* Single failure point with 'in' pattern - invert JMPNOT to JMPIF */
+ s->iseq[fail_pos - 2] = OP_JMPIF;
+ match_pos = fail_pos;
+ }
+ else {
+ /* Multiple failure points - need JMP to skip error handling */
+ match_pos = genjmp(s, OP_JMP, JMPLINK_START);
+ dispatch_linked(s, fail_pos);
+ }
+
+ /* Failure path: restore stack pointer (value still on stack at runtime) */
+ s->sp = saved_sp;
+ pop(); /* pop the value */
+ if (mp->raise_on_fail) {
+ /* expr => pattern: raise NoMatchingPatternError */
+ genop_1(s, OP_LOADFALSE, cursp()); /* Load false for MATCHERR */
+ genop_1(s, OP_MATCHERR, cursp());
+ }
+ else {
+ /* expr in pattern: return false */
+ if (val) {
+ genop_1(s, OP_LOADFALSE, cursp());
+ push();
+ }
}
+
+ /* End of pattern matching */
+ dispatch(s, match_pos);
+ /* Restore sp to match success path value */
+ s->sp = saved_sp - 1;
if (val) push();
- break;
+ }
+ else {
+ /* Pattern always matches - pop value and push result if needed */
+ pop(); /* pop the value */
+ if (val) {
+ if (mp->raise_on_fail) {
+ gen_load_nil(s, 1); /* '=>' pattern returns nil */
+ }
+ else {
+ genop_1(s, OP_LOADTRUE, cursp()); /* 'in' pattern returns true */
+ push();
+ }
+ }
}
}
break;
- case NODE_STR:
- if (val) {
- char *p = (char*)tree->car;
- mrb_int len = nint(tree->cdr);
- int off = new_lit_str(s, p, len);
+ case NODE_DEF:
+ codegen_def(s, tree, val);
+ break;
- genop_2(s, OP_STRING, cursp(), off);
- push();
- }
+ case NODE_CLASS:
+ codegen_class(s, tree, val);
break;
- case NODE_HEREDOC:
- tree = ((struct mrb_parser_heredoc_info*)tree)->doc;
- /* fall through */
- case NODE_DSTR:
- if (val) {
- node *n = tree;
+ case NODE_MODULE:
+ codegen_module(s, tree, val);
+ break;
- if (!n) {
- genop_1(s, OP_LOADNIL, cursp());
- push();
- break;
- }
- codegen(s, n->car, VAL);
- n = n->cdr;
- while (n) {
- codegen(s, n->car, VAL);
- pop(); pop();
- genop_1(s, OP_STRCAT, cursp());
- push();
- n = n->cdr;
- }
- }
- else {
- node *n = tree;
+ case NODE_SCLASS:
+ codegen_sclass(s, tree, val);
+ break;
- while (n) {
- if (nint(n->car->car) != NODE_STR) {
- codegen(s, n->car, NOVAL);
- }
- n = n->cdr;
- }
- }
+ case NODE_ASGN:
+ codegen_asgn(s, tree, val);
break;
- case NODE_WORDS:
- gen_literal_array(s, tree, FALSE, val);
+ case NODE_MASGN:
+ codegen_masgn(s, tree, NULL, 0, val);
break;
- case NODE_SYMBOLS:
- gen_literal_array(s, tree, TRUE, val);
+ case NODE_MARG:
+ /* Parameter destructuring should be handled inline by lambda_body */
+ /* This case should not be reached in normal execution */
break;
- case NODE_DXSTR:
- {
- node *n;
- int sym = new_sym(s, MRB_SYM_2(s->mrb, Kernel));
+ case NODE_OP_ASGN:
+ codegen_op_asgn(s, tree, val);
+ break;
- push();
- codegen(s, tree->car, VAL);
- n = tree->cdr;
- while (n) {
- if (nint(n->car->car) == NODE_XSTR) {
- n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR;
- mrb_assert(!n->cdr); /* must be the end */
- }
- codegen(s, n->car, VAL);
- pop(); pop();
- genop_1(s, OP_STRCAT, cursp());
- push();
- n = n->cdr;
- }
- push(); /* for block */
- pop_n(3);
- sym = new_sym(s, MRB_OPSYM_2(s->mrb, tick)); /* ` */
- genop_3(s, OP_SSEND, cursp(), sym, 1);
- if (val) push();
- }
+ case NODE_AND:
+ codegen_and(s, tree, val);
break;
- case NODE_XSTR:
- {
- char *p = (char*)tree->car;
- mrb_int len = nint(tree->cdr);
- int off = new_lit_str(s, p, len);
- int sym;
+ case NODE_OR:
+ codegen_or(s, tree, val);
+ break;
- genop_1(s, OP_LOADSELF, cursp());
- push();
- genop_2(s, OP_STRING, cursp(), off);
- push(); push();
- pop_n(3);
- sym = new_sym(s, MRB_OPSYM_2(s->mrb, tick)); /* ` */
- genop_3(s, OP_SEND, cursp(), sym, 1);
- if (val) push();
- }
+ case NODE_RETURN:
+ codegen_return(s, tree, val);
break;
- case NODE_REGX:
- if (val) {
- char *p1 = (char*)tree->car;
- char *p2 = (char*)tree->cdr->car;
- char *p3 = (char*)tree->cdr->cdr;
- int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS));
- int off = new_lit_cstr(s, p1);
- int argc = 1;
-
- genop_1(s, OP_OCLASS, cursp());
- genop_2(s, OP_GETMCNST, cursp(), sym);
- push();
- genop_2(s, OP_STRING, cursp(), off);
- push();
- if (p2 || p3) {
- if (p2) { /* opt */
- off = new_lit_cstr(s, p2);
- genop_2(s, OP_STRING, cursp(), off);
- }
- else {
- genop_1(s, OP_LOADNIL, cursp());
- }
- push();
- argc++;
- if (p3) { /* enc */
- off = new_lit_str(s, p3, 1);
- genop_2(s, OP_STRING, cursp(), off);
- push();
- argc++;
- }
- }
- push(); /* space for a block */
- pop_n(argc+2);
- sym = new_sym(s, MRB_SYM_2(s->mrb, compile));
- genop_3(s, OP_SEND, cursp(), sym, argc);
- push();
- }
+ case NODE_YIELD:
+ codegen_yield(s, tree, val);
break;
- case NODE_DREGX:
- if (val) {
- node *n = tree->car;
- int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS));
- int argc = 1;
- int off;
- char *p;
-
- genop_1(s, OP_OCLASS, cursp());
- genop_2(s, OP_GETMCNST, cursp(), sym);
- push();
- codegen(s, n->car, VAL);
- n = n->cdr;
- while (n) {
- codegen(s, n->car, VAL);
- pop(); pop();
- genop_1(s, OP_STRCAT, cursp());
- push();
- n = n->cdr;
- }
- n = tree->cdr->cdr;
- if (n->car) { /* tail */
- p = (char*)n->car;
- off = new_lit_cstr(s, p);
- codegen(s, tree->car, VAL);
- genop_2(s, OP_STRING, cursp(), off);
- pop();
- genop_1(s, OP_STRCAT, cursp());
- push();
- }
- if (n->cdr->car) { /* opt */
- char *p2 = (char*)n->cdr->car;
- off = new_lit_cstr(s, p2);
- genop_2(s, OP_STRING, cursp(), off);
- push();
- argc++;
- }
- if (n->cdr->cdr) { /* enc */
- char *p2 = (char*)n->cdr->cdr;
- off = new_lit_cstr(s, p2);
- genop_2(s, OP_STRING, cursp(), off);
- push();
- argc++;
- }
- push(); /* space for a block */
- pop_n(argc+2);
- sym = new_sym(s, MRB_SYM_2(s->mrb, compile));
- genop_3(s, OP_SEND, cursp(), sym, argc);
- push();
- }
- else {
- node *n = tree->car;
+ case NODE_SUPER:
+ codegen_super(s, tree, val);
+ break;
- while (n) {
- if (nint(n->car->car) != NODE_STR) {
- codegen(s, n->car, NOVAL);
- }
- n = n->cdr;
- }
- }
+ case NODE_STR:
+ codegen_str(s, tree, val);
break;
- case NODE_SYM:
- if (val) {
- int sym = new_sym(s, nsym(tree));
+ case NODE_DOT2:
+ codegen_dot2(s, tree, val);
+ break;
- genop_2(s, OP_LOADSYM, cursp(), sym);
- push();
- }
+ case NODE_DOT3:
+ codegen_dot3(s, tree, val);
break;
- case NODE_DSYM:
- codegen(s, tree, val);
- if (val) {
- gen_intern(s);
- }
+ case NODE_FLOAT:
+ codegen_float(s, tree, val);
break;
case NODE_SELF:
- if (val) {
- genop_1(s, OP_LOADSELF, cursp());
- push();
- }
+ codegen_self(s, tree, val);
break;
case NODE_NIL:
- if (val) {
- genop_1(s, OP_LOADNIL, cursp());
- push();
- }
+ codegen_nil(s, tree, val);
break;
case NODE_TRUE:
- if (val) {
- genop_1(s, OP_LOADT, cursp());
- push();
- }
+ codegen_true(s, tree, val);
break;
case NODE_FALSE:
- if (val) {
- genop_1(s, OP_LOADF, cursp());
- push();
- }
+ codegen_false(s, tree, val);
break;
- case NODE_ALIAS:
- {
- int a = new_sym(s, nsym(tree->car));
- int b = new_sym(s, nsym(tree->cdr));
+ case NODE_CONST:
+ codegen_const(s, tree, val);
+ break;
- genop_2(s, OP_ALIAS, a, b);
- if (val) {
- genop_1(s, OP_LOADNIL, cursp());
- push();
- }
- }
- break;
+ case NODE_RESCUE:
+ codegen_rescue(s, tree, val);
+ break;
- case NODE_UNDEF:
- {
- node *t = tree;
+ case NODE_BLOCK:
+ codegen_block(s, tree, val);
+ break;
- while (t) {
- int symbol = new_sym(s, nsym(t->car));
- genop_1(s, OP_UNDEF, symbol);
- t = t->cdr;
- }
- if (val) {
- genop_1(s, OP_LOADNIL, cursp());
- push();
- }
- }
+ case NODE_BREAK:
+ codegen_break(s, tree, val);
break;
- case NODE_CLASS:
- {
- int idx;
- node *body;
+ case NODE_NEXT:
+ codegen_next(s, tree, val);
+ break;
- if (tree->car->car == (node*)0) {
- genop_1(s, OP_LOADNIL, cursp());
- push();
- }
- else if (tree->car->car == (node*)1) {
- genop_1(s, OP_OCLASS, cursp());
- push();
- }
- else {
- codegen(s, tree->car->car, VAL);
- }
- if (tree->cdr->car) {
- codegen(s, tree->cdr->car, VAL);
- }
- else {
- genop_1(s, OP_LOADNIL, cursp());
- push();
- }
- pop(); pop();
- idx = new_sym(s, nsym(tree->car->cdr));
- genop_2(s, OP_CLASS, cursp(), idx);
- body = tree->cdr->cdr->car;
- if (nint(body->cdr->car) == NODE_BEGIN && body->cdr->cdr == NULL) {
- genop_1(s, OP_LOADNIL, cursp());
- }
- else {
- idx = scope_body(s, body, val);
- genop_2(s, OP_EXEC, cursp(), idx);
- }
- if (val) {
- push();
- }
- }
+ case NODE_REDO:
+ codegen_redo(s, tree, val);
break;
- case NODE_MODULE:
- {
- int idx;
+ case NODE_RETRY:
+ codegen_retry(s, tree, val);
+ break;
- if (tree->car->car == (node*)0) {
- genop_1(s, OP_LOADNIL, cursp());
- push();
- }
- else if (tree->car->car == (node*)1) {
- genop_1(s, OP_OCLASS, cursp());
- push();
- }
- else {
- codegen(s, tree->car->car, VAL);
- }
- pop();
- idx = new_sym(s, nsym(tree->car->cdr));
- genop_2(s, OP_MODULE, cursp(), idx);
- if (nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
- tree->cdr->car->cdr->cdr == NULL) {
- genop_1(s, OP_LOADNIL, cursp());
- }
- else {
- idx = scope_body(s, tree->cdr->car, val);
- genop_2(s, OP_EXEC, cursp(), idx);
- }
- if (val) {
- push();
- }
- }
+ case NODE_WHILE_MOD:
+ codegen_while_mod(s, tree, val);
break;
- case NODE_SCLASS:
- {
- int idx;
+ case NODE_UNTIL_MOD:
+ codegen_until_mod(s, tree, val);
+ break;
- codegen(s, tree->car, VAL);
- pop();
- genop_1(s, OP_SCLASS, cursp());
- if (nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
- tree->cdr->car->cdr->cdr == NULL) {
- genop_1(s, OP_LOADNIL, cursp());
- }
- else {
- idx = scope_body(s, tree->cdr->car, val);
- genop_2(s, OP_EXEC, cursp(), idx);
- }
- if (val) {
- push();
- }
- }
+ case NODE_XSTR:
+ codegen_xstr(s, tree, val);
break;
- case NODE_DEF:
- {
- int sym = new_sym(s, nsym(tree->car));
- int idx = lambda_body(s, tree->cdr, 0);
+ case NODE_REGX:
+ codegen_regx(s, tree, val);
+ break;
- genop_1(s, OP_TCLASS, cursp());
- push();
- genop_2(s, OP_METHOD, cursp(), idx);
- push(); pop();
- pop();
- genop_2(s, OP_DEF, cursp(), sym);
- if (val) push();
- }
+ case NODE_HEREDOC:
+ codegen_heredoc(s, tree, val);
break;
- case NODE_SDEF:
- {
- node *recv = tree->car;
- int sym = new_sym(s, nsym(tree->cdr->car));
- int idx = lambda_body(s, tree->cdr->cdr, 0);
+ case NODE_DSYM:
+ codegen_dsym(s, tree, val);
+ break;
- codegen(s, recv, VAL);
- pop();
- genop_1(s, OP_SCLASS, cursp());
- push();
- genop_2(s, OP_METHOD, cursp(), idx);
- push(); pop();
- pop();
- genop_2(s, OP_DEF, cursp(), sym);
- if (val) push();
- }
+ case NODE_NTH_REF:
+ codegen_nth_ref(s, tree, val);
+ break;
+
+ case NODE_BACK_REF:
+ codegen_back_ref(s, tree, val);
+ break;
+
+ case NODE_NVAR:
+ codegen_nvar(s, tree, val);
+ break;
+
+ case NODE_DVAR:
+ codegen_dvar(s, tree, val);
+ break;
+
+ case NODE_NOT:
+ codegen_not(s, tree, val);
+ break;
+
+ case NODE_NEGATE:
+ codegen_negate(s, tree, val);
+ break;
+
+ case NODE_COLON2:
+ codegen_colon2(s, tree, val);
+ break;
+
+ case NODE_COLON3:
+ codegen_colon3(s, tree, val);
+ break;
+
+ case NODE_DEFINED:
+ codegen_defined(s, tree, val);
+ break;
+
+ case NODE_ZSUPER:
+ codegen_zsuper(s, tree, val);
+ break;
+
+ case NODE_LAMBDA:
+ codegen_lambda(s, tree, val);
+ break;
+
+ case NODE_WORDS:
+ codegen_words(s, tree, val);
+ break;
+
+ case NODE_SYMBOLS:
+ codegen_symbols(s, tree, val);
+ break;
+
+ case NODE_SPLAT:
+ codegen_splat(s, tree, val);
+ break;
+
+ case NODE_BLOCK_ARG:
+ codegen_block_arg(s, tree, val);
+ break;
+
+ case NODE_SCOPE:
+ codegen_scope_node(s, tree, val);
+ break;
+
+ case NODE_BEGIN:
+ codegen_begin(s, tree, val);
+ break;
+
+ case NODE_ENSURE:
+ codegen_ensure(s, tree, val);
+ break;
+
+ case NODE_STMTS:
+ codegen_stmts(s, tree, val);
+ break;
+
+ case NODE_ALIAS:
+ codegen_alias(s, tree, val);
+ break;
+
+ case NODE_UNDEF:
+ codegen_undef(s, tree, val);
break;
case NODE_POSTEXE:
- codegen(s, tree, NOVAL);
+ {
+ struct mrb_ast_postexe_node *postexe = postexe_node(tree);
+ codegen(s, postexe->body, NOVAL);
+ }
+ break;
+
+ case NODE_SDEF:
+ codegen_sdef(s, tree, val);
break;
default:
+ /* Unhandled variable-sized node type - should not occur with current AST */
break;
}
- exit:
s->rlev = rlev;
}
@@ -3969,7 +7068,7 @@ scope_add_irep(codegen_scope *s)
s->irep = irep = mrb_add_irep(s->mrb);
if (prev->irep->rlen == prev->rcapa) {
prev->rcapa *= 2;
- prev->reps = (mrb_irep**)codegen_realloc(s, prev->reps, sizeof(mrb_irep*)*prev->rcapa);
+ prev->reps = (mrb_irep**)mrbc_realloc(prev->reps, sizeof(mrb_irep*)*prev->rcapa);
}
prev->reps[prev->irep->rlen] = irep;
prev->irep->rlen++;
@@ -3980,8 +7079,8 @@ static codegen_scope*
scope_new(mrb_state *mrb, codegen_scope *prev, node *nlv)
{
static const codegen_scope codegen_scope_zero = { 0 };
- mrb_mempool *pool = mrb_mempool_open(mrb);
- codegen_scope *s = (codegen_scope*)mrb_mempool_alloc(pool, sizeof(codegen_scope));
+ mempool *pool = mempool_open();
+ codegen_scope *s = (codegen_scope*)mempool_alloc(pool, sizeof(codegen_scope));
if (!s) {
if (prev)
@@ -3999,26 +7098,26 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *nlv)
scope_add_irep(s);
s->rcapa = 8;
- s->reps = (mrb_irep**)mrb_malloc(mrb, sizeof(mrb_irep*)*s->rcapa);
+ s->reps = (mrb_irep**)mrbc_malloc(sizeof(mrb_irep*)*s->rcapa);
s->icapa = 1024;
- s->iseq = (mrb_code*)mrb_malloc(mrb, sizeof(mrb_code)*s->icapa);
+ s->iseq = (mrb_code*)mrbc_malloc(sizeof(mrb_code)*s->icapa);
s->pcapa = 32;
- s->pool = (mrb_irep_pool*)mrb_malloc(mrb, sizeof(mrb_irep_pool)*s->pcapa);
+ s->pool = (mrb_irep_pool*)mrbc_malloc(sizeof(mrb_irep_pool)*s->pcapa);
s->scapa = 256;
- s->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*s->scapa);
+ s->syms = (mrb_sym*)mrbc_malloc(sizeof(mrb_sym)*s->scapa);
s->lv = nlv;
- s->sp += node_len(nlv)+1; /* add self */
- s->nlocals = s->sp;
+ s->sp += (nlv ? node_len(nlv) : 0) + 1; /* add self */
+ s->nlocals = s->nregs = s->sp;
if (nlv) {
mrb_sym *lv;
node *n = nlv;
size_t i = 0;
- s->irep->lv = lv = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*(s->nlocals-1));
+ s->irep->lv = lv = (mrb_sym*)mrbc_malloc(sizeof(mrb_sym)*(s->nlocals-1));
for (i=0, n=nlv; n; i++,n=n->cdr) {
lv[i] = lv_name(n);
}
@@ -4028,7 +7127,7 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *nlv)
s->filename_sym = prev->filename_sym;
if (s->filename_sym) {
- s->lines = (uint16_t*)mrb_malloc(mrb, sizeof(short)*s->icapa);
+ s->lines = (uint16_t*)mrbc_malloc(sizeof(short)*s->icapa);
}
s->lineno = prev->lineno;
@@ -4060,7 +7159,7 @@ scope_finish(codegen_scope *s)
irep->flags = 0;
if (s->iseq) {
size_t catchsize = sizeof(struct mrb_irep_catch_handler) * irep->clen;
- irep->iseq = (const mrb_code*)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc + catchsize);
+ irep->iseq = (const mrb_code*)mrbc_realloc(s->iseq, sizeof(mrb_code)*s->pc + catchsize);
irep->ilen = s->pc;
if (irep->clen > 0) {
memcpy((void*)(irep->iseq + irep->ilen), s->catch_table, catchsize);
@@ -4069,11 +7168,11 @@ scope_finish(codegen_scope *s)
else {
irep->clen = 0;
}
- mrb_free(s->mrb, s->catch_table);
+ mrbc_free(s->catch_table);
s->catch_table = NULL;
- irep->pool = (const mrb_irep_pool*)codegen_realloc(s, s->pool, sizeof(mrb_irep_pool)*irep->plen);
- irep->syms = (const mrb_sym*)codegen_realloc(s, s->syms, sizeof(mrb_sym)*irep->slen);
- irep->reps = (const mrb_irep**)codegen_realloc(s, s->reps, sizeof(mrb_irep*)*irep->rlen);
+ irep->pool = (const mrb_irep_pool*)mrbc_realloc(s->pool, sizeof(mrb_irep_pool)*irep->plen);
+ irep->syms = (const mrb_sym*)mrbc_realloc(s->syms, sizeof(mrb_sym)*irep->slen);
+ irep->reps = (const mrb_irep**)mrbc_realloc(s->reps, sizeof(mrb_irep*)*irep->rlen);
if (s->filename_sym) {
mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index);
const char *filename = mrb_sym_name_len(s->mrb, fname, NULL);
@@ -4081,13 +7180,13 @@ scope_finish(codegen_scope *s)
mrb_debug_info_append_file(s->mrb, s->irep->debug_info,
filename, s->lines, s->debug_start_pos, s->pc);
}
- mrb_free(s->mrb, s->lines);
+ mrbc_free(s->lines);
irep->nlocals = s->nlocals;
irep->nregs = s->nregs;
mrb_gc_arena_restore(mrb, s->ai);
- mrb_mempool_close(s->mpool);
+ mempool_close(s->mpool);
}
static struct loopinfo*
@@ -4114,7 +7213,6 @@ loop_break(codegen_scope *s, node *tree)
else {
struct loopinfo *loop;
-
loop = s->loop;
if (tree) {
if (loop->reg < 0) {
@@ -4178,7 +7276,7 @@ static int
catch_handler_new(codegen_scope *s)
{
size_t newsize = sizeof(struct mrb_irep_catch_handler) * (s->irep->clen + 1);
- s->catch_table = (struct mrb_irep_catch_handler*)codegen_realloc(s, (void*)s->catch_table, newsize);
+ s->catch_table = (struct mrb_irep_catch_handler*)mrbc_realloc((void*)s->catch_table, newsize);
return s->irep->clen++;
}
@@ -4216,7 +7314,7 @@ generate_code(mrb_state *mrb, parser_state *p, int val)
codegen(scope, p->tree, val);
proc = mrb_proc_new(mrb, scope->irep);
mrb_irep_decref(mrb, scope->irep);
- mrb_mempool_close(scope->mpool);
+ mempool_close(scope->mpool);
proc->c = NULL;
if (mrb->c->cibase && mrb->c->cibase->proc == proc->upper) {
proc->upper = NULL;
@@ -4226,15 +7324,16 @@ generate_code(mrb_state *mrb, parser_state *p, int val)
}
MRB_CATCH(mrb->jmp) {
mrb_irep_decref(mrb, scope->irep);
- mrb_mempool_close(scope->mpool);
+ mempool_close(scope->mpool);
mrb->jmp = prev_jmp;
return NULL;
}
MRB_END_EXC(mrb->jmp);
}
+
MRB_API struct RProc*
mrb_generate_code(mrb_state *mrb, parser_state *p)
{
- return generate_code(mrb, p, VAL);
+ return generate_code(mrb, p, p->no_return_value ? NOVAL : VAL);
}
diff --git a/mrbgems/mruby-compiler/core/node.h b/mrbgems/mruby-compiler/core/node.h
index a57b7bd..beb507b 100644
--- a/mrbgems/mruby-compiler/core/node.h
+++ b/mrbgems/mruby-compiler/core/node.h
@@ -8,20 +8,20 @@
#define MRUBY_COMPILER_NODE_H
enum node_type {
- NODE_METHOD,
NODE_SCOPE,
NODE_BLOCK,
NODE_IF,
NODE_CASE,
- NODE_WHEN,
NODE_WHILE,
NODE_UNTIL,
- NODE_ITER,
+ NODE_WHILE_MOD,
+ NODE_UNTIL_MOD,
NODE_FOR,
NODE_BREAK,
NODE_NEXT,
NODE_REDO,
NODE_RETRY,
+ NODE_STMTS,
NODE_BEGIN,
NODE_RESCUE,
NODE_ENSURE,
@@ -29,20 +29,15 @@ enum node_type {
NODE_OR,
NODE_NOT,
NODE_MASGN,
+ NODE_MARG,
NODE_ASGN,
- NODE_CDECL,
- NODE_CVASGN,
- NODE_CVDECL,
NODE_OP_ASGN,
NODE_CALL,
- NODE_SCALL,
- NODE_FCALL,
NODE_SUPER,
NODE_ZSUPER,
NODE_ARRAY,
NODE_ZARRAY,
NODE_HASH,
- NODE_KW_HASH,
NODE_RETURN,
NODE_YIELD,
NODE_LVAR,
@@ -54,26 +49,16 @@ enum node_type {
NODE_NVAR,
NODE_NTH_REF,
NODE_BACK_REF,
- NODE_MATCH,
NODE_INT,
+ NODE_BIGINT,
NODE_FLOAT,
NODE_NEGATE,
NODE_LAMBDA,
NODE_SYM,
NODE_STR,
- NODE_DSTR,
NODE_XSTR,
- NODE_DXSTR,
NODE_REGX,
- NODE_DREGX,
- NODE_DREGX_ONCE,
- NODE_ARG,
- NODE_ARGS_TAIL,
- NODE_KW_ARG,
- NODE_KW_REST_ARGS,
NODE_SPLAT,
- NODE_TO_ARY,
- NODE_SVALUE,
NODE_BLOCK_ARG,
NODE_DEF,
NODE_SDEF,
@@ -94,10 +79,706 @@ enum node_type {
NODE_POSTEXE,
NODE_DSYM,
NODE_HEREDOC,
- NODE_LITERAL_DELIM,
NODE_WORDS,
NODE_SYMBOLS,
+ /* Pattern matching nodes */
+ NODE_CASE_MATCH, /* case/in pattern matching expression */
+ NODE_IN, /* in-clause node */
+ NODE_PAT_VALUE, /* value pattern (literal, constant) */
+ NODE_PAT_VAR, /* variable pattern */
+ NODE_PAT_PIN, /* pin operator ^var */
+ NODE_PAT_AS, /* as pattern (pattern => var) */
+ NODE_PAT_ALT, /* alternative pattern (pat1 | pat2) */
+ NODE_PAT_ARRAY, /* array pattern [a, b, *rest] */
+ NODE_PAT_FIND, /* find pattern [*pre, elem, *post] */
+ NODE_PAT_HASH, /* hash pattern {a:, b: x} */
+ NODE_MATCH_PAT, /* one-line pattern matching (expr in pat / expr => pat) */
NODE_LAST
};
+#define STR_FUNC_PARSING 0x01
+#define STR_FUNC_EXPAND 0x02
+#define STR_FUNC_REGEXP 0x04
+#define STR_FUNC_WORD 0x08
+#define STR_FUNC_SYMBOL 0x10
+#define STR_FUNC_ARRAY 0x20
+#define STR_FUNC_HEREDOC 0x40
+#define STR_FUNC_XQUOTE 0x80
+
+enum mrb_string_type {
+ str_not_parsing = (0),
+ str_squote = (STR_FUNC_PARSING),
+ str_dquote = (STR_FUNC_PARSING|STR_FUNC_EXPAND),
+ str_regexp = (STR_FUNC_PARSING|STR_FUNC_REGEXP|STR_FUNC_EXPAND),
+ str_sword = (STR_FUNC_PARSING|STR_FUNC_WORD|STR_FUNC_ARRAY),
+ str_dword = (STR_FUNC_PARSING|STR_FUNC_WORD|STR_FUNC_ARRAY|STR_FUNC_EXPAND),
+ str_ssym = (STR_FUNC_PARSING|STR_FUNC_SYMBOL),
+ str_ssymbols = (STR_FUNC_PARSING|STR_FUNC_SYMBOL|STR_FUNC_ARRAY),
+ str_dsymbols = (STR_FUNC_PARSING|STR_FUNC_SYMBOL|STR_FUNC_ARRAY|STR_FUNC_EXPAND),
+ str_heredoc = (STR_FUNC_PARSING|STR_FUNC_HEREDOC),
+ str_xquote = (STR_FUNC_PARSING|STR_FUNC_XQUOTE|STR_FUNC_EXPAND),
+};
+
+/* heredoc structure */
+struct mrb_parser_heredoc_info {
+ mrb_bool allow_indent:1;
+ mrb_bool remove_indent:1;
+ mrb_bool line_head:1;
+ size_t indent;
+ mrb_ast_node *indented;
+ enum mrb_string_type type;
+ const char *term;
+ int term_len;
+ mrb_ast_node *doc;
+};
+
+/* AST node structures - Head-only location optimization */
+
+/* Structure nodes - only car/cdr, ignores location fields */
+struct mrb_ast_node {
+ struct mrb_ast_node *car, *cdr;
+ /* No location fields - saves 4 bytes per structure node */
+};
+
+/* Variable-sized AST nodes */
+
+/* Variable node header - common to all variable-sized nodes */
+struct mrb_ast_var_header {
+ uint16_t lineno; /* Line number information */
+ uint16_t filename_index; /* File index information */
+ uint8_t node_type; /* NODE_INT, NODE_SYM, NODE_STR, etc. */
+ /* Total: 6 bytes header for all variable nodes */
+};
+
+/* Literal value nodes */
+
+/* Variable-sized symbol node */
+struct mrb_ast_sym_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ mrb_sym symbol; /* Direct symbol reference */
+ /* Total: 12-16 bytes vs previous 20+ bytes + indirection */
+};
+
+/* Variable-sized string node with cons list */
+struct mrb_ast_str_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *list;
+};
+
+/* Variable-sized integer node */
+struct mrb_ast_int_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ int32_t value; /* Direct 32-bit integer storage */
+};
+
+/* Variable-sized big integer node */
+struct mrb_ast_bigint_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ char *string; /* String representation of big number */
+ int base; /* Number base (8, 10, 16) */
+};
+
+/* Variable-sized node for variables (lvar, ivar, etc.) */
+struct mrb_ast_var_node {
+ struct mrb_ast_var_header header;
+ mrb_sym symbol;
+};
+
+/* Expression and operation nodes */
+
+/* Variable-sized call node with inline argument storage */
+struct mrb_ast_call_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *receiver; /* Receiver object */
+ mrb_sym method_name; /* Method name symbol */
+ uint8_t safe_call:1; /* Safe navigation (&.) */
+ struct mrb_ast_node *args; /* Arguments Information */
+};
+
+/* Variable-sized array node */
+struct mrb_ast_array_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *elements; /* Elements list (cons list) */
+};
+
+/* Variable-sized hash node */
+struct mrb_ast_hash_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *pairs; /* Key-value pairs (cons list) */
+};
+
+/* Control flow and definition nodes */
+
+/* Variable-sized method definition node */
+struct mrb_ast_def_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ mrb_sym name; /* Method name */
+ struct mrb_ast_args *args; /* Method arguments */
+ struct mrb_ast_node *body; /* Method body */
+ struct mrb_ast_node *locals; /* Local Variables */
+} ;
+
+/* Variable-sized singleton method definition node */
+struct mrb_ast_sdef_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ mrb_sym name; /* Method name */
+ struct mrb_ast_args *args; /* Method arguments */
+ struct mrb_ast_node *body; /* Method body */
+ struct mrb_ast_node *locals; /* Local Variables */
+ struct mrb_ast_node *obj; /* receiver */
+};
+
+/* variable-sized class definition node */
+struct mrb_ast_class_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *name; /* Class name (NODE_CONST or NODE_COLON2) */
+ struct mrb_ast_node *superclass; /* Superclass (can be NULL) */
+ struct mrb_ast_node *body; /* Class body */
+};
+
+/* Variable-sized module definition node */
+struct mrb_ast_module_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *name; /* Module name (NODE_CONST or NODE_COLON2) */
+ struct mrb_ast_node *body; /* Module body */
+};
+
+/* Variable-sized singleton class definition node */
+struct mrb_ast_sclass_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *obj; /* Object for singleton class */
+ struct mrb_ast_node *body; /* Singleton class body */
+};
+
+/* Variable-sized if node */
+struct mrb_ast_if_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *condition; /* Condition expression */
+ struct mrb_ast_node *then_body; /* Then branch */
+ struct mrb_ast_node *else_body; /* Else branch (can be NULL) */
+};
+
+/* Variable-sized while node */
+struct mrb_ast_while_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *condition; /* Loop condition */
+ struct mrb_ast_node *body; /* Loop body */
+};
+
+/* Variable-sized until node */
+struct mrb_ast_until_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *condition; /* Loop condition */
+ struct mrb_ast_node *body; /* Loop body */
+};
+
+/* Variable-sized case node */
+struct mrb_ast_case_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *value; /* Case value expression */
+ struct mrb_ast_node *body; /* When/else clauses (cons list) */
+};
+
+/* Pattern matching case node (case/in) */
+struct mrb_ast_case_match_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *value; /* Case value expression */
+ struct mrb_ast_node *in_clauses; /* In clause list (cons list) */
+};
+
+/* In clause node */
+struct mrb_ast_in_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *pattern; /* Pattern to match */
+ struct mrb_ast_node *guard; /* Guard expression (optional) */
+ struct mrb_ast_node *body; /* Body to execute on match */
+ mrb_bool guard_is_unless; /* TRUE if 'unless', FALSE if 'if' */
+};
+
+/* Value pattern node (literal, constant) */
+struct mrb_ast_pat_value_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *value; /* Literal or constant node */
+};
+
+/* Variable pattern node */
+struct mrb_ast_pat_var_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ mrb_sym name; /* Variable name (0 for wildcard _) */
+};
+
+/* Pin pattern node (^var) */
+struct mrb_ast_pat_pin_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ mrb_sym name; /* Variable name to pin */
+};
+
+/* As pattern node (pattern => var) */
+struct mrb_ast_pat_as_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *pattern; /* Pattern to match */
+ mrb_sym name; /* Variable to bind */
+};
+
+/* Alternative pattern node (pat1 | pat2) */
+struct mrb_ast_pat_alt_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *left; /* Left pattern */
+ struct mrb_ast_node *right; /* Right pattern */
+};
+
+/* Array pattern node [a, b, *rest] */
+struct mrb_ast_pat_array_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *pre; /* Pre-rest patterns (cons list) */
+ struct mrb_ast_node *rest; /* Rest pattern (NULL if none, -1 if anonymous) */
+ struct mrb_ast_node *post; /* Post-rest patterns (cons list) */
+};
+
+/* Find pattern node [*pre, elem, *post] - searches for elem anywhere in array */
+struct mrb_ast_pat_find_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *pre; /* Pre rest pattern (NULL or -1 if anonymous) */
+ struct mrb_ast_node *elems; /* Middle patterns to find (cons list) */
+ struct mrb_ast_node *post; /* Post rest pattern (NULL or -1 if anonymous) */
+};
+
+/* Hash pattern node {a:, b: x} */
+struct mrb_ast_pat_hash_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *pairs; /* Key-pattern pairs (cons list) */
+ struct mrb_ast_node *rest; /* Rest pattern (NULL if none, -1 if **nil) */
+};
+
+/* One-line pattern matching: expr in pattern / expr => pattern */
+struct mrb_ast_match_pat_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *value; /* Expression to match */
+ struct mrb_ast_node *pattern; /* Pattern */
+ mrb_bool raise_on_fail; /* TRUE for =>, FALSE for in */
+};
+
+/* Variable-sized for node */
+struct mrb_ast_for_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *var; /* Loop variable */
+ struct mrb_ast_node *iterable; /* Object to iterate over */
+ struct mrb_ast_node *body; /* Loop body */
+};
+
+/* Assignment Node Structures */
+
+/* Variable-sized assignment node */
+struct mrb_ast_asgn_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *lhs; /* Left-hand side (target) */
+ struct mrb_ast_node *rhs; /* Right-hand side (value) */
+};
+
+/* Variable-sized multiple assignment node */
+struct mrb_ast_masgn_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *pre; /* Pre-splat variables (cons list) */
+ struct mrb_ast_node *rest; /* Splat variable (single node or -1) */
+ struct mrb_ast_node *post; /* Post-splat variables (cons list) */
+ struct mrb_ast_node *rhs; /* Right-hand side (values) */
+};
+
+/* Variable-sized operator assignment node */
+struct mrb_ast_op_asgn_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *lhs; /* Left-hand side (target) */
+ mrb_sym op; /* Assignment operator (e.g., +=, -=, etc.) */
+ struct mrb_ast_node *rhs; /* Right-hand side (value) */
+};
+
+/* Expression Node Structures */
+
+/* Variable-sized AND node */
+struct mrb_ast_and_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *left; /* Left operand */
+ struct mrb_ast_node *right; /* Right operand */
+};
+
+/* Variable-sized OR node */
+struct mrb_ast_or_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *left; /* Left operand */
+ struct mrb_ast_node *right; /* Right operand */
+};
+
+/* Variable-sized RETURN node */
+struct mrb_ast_return_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *args; /* Return arguments (can be NULL) */
+};
+
+/* Variable-sized YIELD node */
+struct mrb_ast_yield_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *args; /* Yield arguments (can be NULL) */
+};
+
+/* Variable-sized SUPER node */
+struct mrb_ast_super_node {
+ struct mrb_ast_var_header header; /* 8 bytes */
+ struct mrb_ast_node *args; /* Super arguments (can be NULL) */
+};
+
+#define NODE_TYPE(n) ((enum node_type)(((struct mrb_ast_var_header*)(n))->node_type))
+
+/* Type-safe casting macros */
+#define var_header(n) ((struct mrb_ast_var_header*)(n))
+
+/* Common type casting macros used by parser and codegen */
+#define node_to_sym(x) ((mrb_sym)(intptr_t)(x))
+#define sym_to_node(x) ((node*)(intptr_t)(x))
+#define int_to_node(x) ((node*)(intptr_t)(x))
+#define node_to_int(x) ((int)(intptr_t)(x))
+#define node_to_type(x) ((enum node_type)(intptr_t)(x))
+#define node_to_char(x) ((char)(intptr_t)(x))
+
+/* Literal value node casting macros */
+#define sym_node(n) ((struct mrb_ast_sym_node*)(n))
+#define str_node(n) ((struct mrb_ast_str_node*)(n))
+#define int_node(n) ((struct mrb_ast_int_node*)(n))
+#define bigint_node(n) ((struct mrb_ast_bigint_node*)(n))
+#define var_node(n) ((struct mrb_ast_var_node*)(n))
+
+/* Expression and operation node casting macros */
+#define call_node(n) ((struct mrb_ast_call_node*)(n))
+#define array_node(n) ((struct mrb_ast_array_node*)(n))
+#define hash_node(n) ((struct mrb_ast_hash_node*)(n))
+
+/* Control flow and definition node casting macros */
+#define def_node(n) ((struct mrb_ast_def_node*)(n))
+#define class_node(n) ((struct mrb_ast_class_node*)(n))
+#define module_node(n) ((struct mrb_ast_module_node*)(n))
+#define sclass_node(n) ((struct mrb_ast_sclass_node*)(n))
+#define if_node(n) ((struct mrb_ast_if_node*)(n))
+#define while_node(n) ((struct mrb_ast_while_node*)(n))
+#define until_node(n) ((struct mrb_ast_until_node*)(n))
+#define case_node(n) ((struct mrb_ast_case_node*)(n))
+#define case_match_node(n) ((struct mrb_ast_case_match_node*)(n))
+#define in_node(n) ((struct mrb_ast_in_node*)(n))
+#define pat_value_node(n) ((struct mrb_ast_pat_value_node*)(n))
+#define pat_var_node(n) ((struct mrb_ast_pat_var_node*)(n))
+#define pat_pin_node(n) ((struct mrb_ast_pat_pin_node*)(n))
+#define pat_as_node(n) ((struct mrb_ast_pat_as_node*)(n))
+#define pat_alt_node(n) ((struct mrb_ast_pat_alt_node*)(n))
+#define pat_array_node(n) ((struct mrb_ast_pat_array_node*)(n))
+#define pat_find_node(n) ((struct mrb_ast_pat_find_node*)(n))
+#define pat_hash_node(n) ((struct mrb_ast_pat_hash_node*)(n))
+#define match_pat_node(n) ((struct mrb_ast_match_pat_node*)(n))
+#define for_node(n) ((struct mrb_ast_for_node*)(n))
+#define asgn_node(n) ((struct mrb_ast_asgn_node*)(n))
+#define masgn_node(n) ((struct mrb_ast_masgn_node*)(n))
+#define op_asgn_node(n) ((struct mrb_ast_op_asgn_node*)(n))
+#define and_node(n) ((struct mrb_ast_and_node*)(n))
+#define or_node(n) ((struct mrb_ast_or_node*)(n))
+#define return_node(n) ((struct mrb_ast_return_node*)(n))
+#define yield_node(n) ((struct mrb_ast_yield_node*)(n))
+#define super_node(n) ((struct mrb_ast_super_node*)(n))
+
+/* Variable-sized literal node structures */
+
+struct mrb_ast_dot2_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *left;
+ struct mrb_ast_node *right;
+};
+
+struct mrb_ast_dot3_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *left;
+ struct mrb_ast_node *right;
+};
+
+struct mrb_ast_float_node {
+ struct mrb_ast_var_header header;
+ const char *value;
+};
+
+/* Literal node casting macros */
+#define dot2_node(n) ((struct mrb_ast_dot2_node*)(n))
+#define dot3_node(n) ((struct mrb_ast_dot3_node*)(n))
+#define float_node(n) ((struct mrb_ast_float_node*)(n))
+
+/* Variable-sized simple node structures */
+struct mrb_ast_self_node {
+ struct mrb_ast_var_header header;
+};
+
+struct mrb_ast_nil_node {
+ struct mrb_ast_var_header header;
+};
+
+struct mrb_ast_true_node {
+ struct mrb_ast_var_header header;
+};
+
+struct mrb_ast_false_node {
+ struct mrb_ast_var_header header;
+};
+
+struct mrb_ast_const_node {
+ struct mrb_ast_var_header header;
+ mrb_sym symbol;
+};
+
+/* Simple node casting macros */
+#define self_node(n) ((struct mrb_ast_self_node*)(n))
+#define nil_node(n) ((struct mrb_ast_nil_node*)(n))
+#define true_node(n) ((struct mrb_ast_true_node*)(n))
+#define false_node(n) ((struct mrb_ast_false_node*)(n))
+#define const_node(n) ((struct mrb_ast_const_node*)(n))
+
+/* Variable-sized advanced node structures */
+struct mrb_ast_rescue_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *body;
+ struct mrb_ast_node *rescue_clauses;
+ struct mrb_ast_node *else_clause;
+};
+
+struct mrb_ast_block_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *locals;
+ struct mrb_ast_args *args;
+ struct mrb_ast_node *body;
+};
+
+/* Unified argument structure - eliminates args_tail_node allocation */
+struct mrb_ast_args {
+ /* Core argument lists (parser builds these naturally) */
+ struct mrb_ast_node *mandatory_args; /* Cons list of mandatory arguments */
+ struct mrb_ast_node *optional_args; /* Cons list of optional arguments */
+ struct mrb_ast_node *post_mandatory_args; /* Cons list of post-mandatory arguments */
+ struct mrb_ast_node *keyword_args; /* Cons list of keyword arguments */
+
+ /* Special arguments (directly embedded) */
+ mrb_sym rest_arg; /* Rest argument symbol (0 = none) */
+ mrb_sym kwrest_arg; /* Keyword rest argument (0 = none) */
+ mrb_sym block_arg; /* Block argument symbol (0 = none) */
+};
+
+/* Call arguments structure - replaces cons-based new_callargs */
+struct mrb_ast_callargs {
+ struct mrb_ast_node *regular_args; /* Cons list of regular arguments (preserves splat compatibility) */
+ struct mrb_ast_node *keyword_args; /* Keyword arguments hash node */
+ struct mrb_ast_node *block_arg; /* Block argument node */
+};
+
+/* Advanced node casting macros */
+#define rescue_node(n) ((struct mrb_ast_rescue_node*)(n))
+#define block_node(n) ((struct mrb_ast_block_node*)(n))
+#define callargs_node(n) ((struct mrb_ast_callargs*)(n))
+
+/* Control flow statement nodes */
+struct mrb_ast_break_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *value;
+};
+
+struct mrb_ast_next_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *value;
+};
+
+struct mrb_ast_redo_node {
+ struct mrb_ast_var_header header;
+};
+
+struct mrb_ast_retry_node {
+ struct mrb_ast_var_header header;
+};
+
+#define break_node(n) ((struct mrb_ast_break_node*)(n))
+#define next_node(n) ((struct mrb_ast_next_node*)(n))
+#define redo_node(n) ((struct mrb_ast_redo_node*)(n))
+#define retry_node(n) ((struct mrb_ast_retry_node*)(n))
+
+/* String and regex variant nodes */
+struct mrb_ast_xstr_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *list;
+};
+
+struct mrb_ast_regx_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *list;
+ const char *flags;
+ const char *encoding;
+};
+
+struct mrb_ast_heredoc_node {
+ struct mrb_ast_var_header header;
+ struct mrb_parser_heredoc_info info;
+};
+
+#define xstr_node(n) ((struct mrb_ast_xstr_node*)(n))
+#define regx_node(n) ((struct mrb_ast_regx_node*)(n))
+#define heredoc_node(n) ((struct mrb_ast_heredoc_node*)(n))
+#define dsym_node(n) ((struct mrb_ast_str_node*)(n))
+
+/* Reference and special variable nodes */
+struct mrb_ast_nth_ref_node {
+ struct mrb_ast_var_header header;
+ int nth;
+};
+
+struct mrb_ast_back_ref_node {
+ struct mrb_ast_var_header header;
+ int type;
+};
+
+struct mrb_ast_nvar_node {
+ struct mrb_ast_var_header header;
+ int num;
+};
+
+struct mrb_ast_dvar_node {
+ struct mrb_ast_var_header header;
+ mrb_sym name;
+};
+
+#define nth_ref_node(n) ((struct mrb_ast_nth_ref_node*)(n))
+#define back_ref_node(n) ((struct mrb_ast_back_ref_node*)(n))
+#define nvar_node(n) ((struct mrb_ast_nvar_node*)(n))
+#define dvar_node(n) ((struct mrb_ast_dvar_node*)(n))
+
+/* Unary operator and scope resolution nodes */
+struct mrb_ast_not_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *operand;
+};
+
+struct mrb_ast_negate_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *operand;
+};
+
+struct mrb_ast_colon2_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *base;
+ mrb_sym name;
+};
+
+struct mrb_ast_colon3_node {
+ struct mrb_ast_var_header header;
+ mrb_sym name;
+};
+
+struct mrb_ast_defined_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *expr;
+};
+
+#define not_node(n) ((struct mrb_ast_not_node*)(n))
+#define negate_node(n) ((struct mrb_ast_negate_node*)(n))
+#define colon2_node(n) ((struct mrb_ast_colon2_node*)(n))
+#define colon3_node(n) ((struct mrb_ast_colon3_node*)(n))
+#define defined_node(n) ((struct mrb_ast_defined_node*)(n))
+
+/* Lambda nodes */
+struct mrb_ast_lambda_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *locals;
+ struct mrb_ast_args *args;
+ struct mrb_ast_node *body;
+};
+
+/* Array literal variant nodes */
+struct mrb_ast_zarray_node {
+ struct mrb_ast_var_header header;
+};
+
+struct mrb_ast_words_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *args;
+};
+
+struct mrb_ast_symbols_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *args;
+};
+
+/* Argument and parameter nodes */
+
+struct mrb_ast_splat_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *value;
+};
+
+struct mrb_ast_block_arg_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *value;
+};
+
+/* Structural and block nodes */
+
+struct mrb_ast_scope_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *locals;
+ struct mrb_ast_node *body;
+};
+
+struct mrb_ast_begin_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *body;
+};
+
+struct mrb_ast_ensure_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *body;
+ struct mrb_ast_node *ensure_clause;
+};
+
+struct mrb_ast_stmts_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *stmts; /* Cons-list of statements */
+};
+
+struct mrb_ast_iter_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *vars;
+ struct mrb_ast_node *body;
+};
+
+/* Declaration nodes */
+
+struct mrb_ast_alias_node {
+ struct mrb_ast_var_header header;
+ mrb_sym new_name;
+ mrb_sym old_name;
+};
+
+struct mrb_ast_undef_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *syms;
+};
+
+struct mrb_ast_postexe_node {
+ struct mrb_ast_var_header header;
+ struct mrb_ast_node *body;
+};
+
+#define zsuper_node(n) ((struct mrb_ast_super_node*)(n))
+#define lambda_node(n) ((struct mrb_ast_lambda_node*)(n))
+#define zarray_node(n) ((struct mrb_ast_zarray_node*)(n))
+#define words_node(n) ((struct mrb_ast_words_node*)(n))
+#define symbols_node(n) ((struct mrb_ast_symbols_node*)(n))
+#define splat_node(n) ((struct mrb_ast_splat_node*)(n))
+#define block_arg_node(n) ((struct mrb_ast_block_arg_node*)(n))
+#define scope_node(n) ((struct mrb_ast_scope_node*)(n))
+#define begin_node(n) ((struct mrb_ast_begin_node*)(n))
+#define ensure_node(n) ((struct mrb_ast_ensure_node*)(n))
+#define stmts_node(n) ((struct mrb_ast_stmts_node*)(n))
+#define iter_node(n) ((struct mrb_ast_iter_node*)(n))
+#define alias_node(n) ((struct mrb_ast_alias_node*)(n))
+#define undef_node(n) ((struct mrb_ast_undef_node*)(n))
+#define postexe_node(n) ((struct mrb_ast_postexe_node*)(n))
+#define sdef_node(n) ((struct mrb_ast_sdef_node*)(n))
+
#endif /* MRUBY_COMPILER_NODE_H */
diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y
index 5b40eb5..74727fe 100644
--- a/mrbgems/mruby-compiler/core/parse.y
+++ b/mrbgems/mruby-compiler/core/parse.y
@@ -12,6 +12,7 @@
#define YYSTACK_USE_ALLOCA 1
#include <ctype.h>
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <mruby.h>
@@ -22,11 +23,14 @@
#include <mruby/string.h>
#include <mruby/dump.h>
#include <mruby/internal.h>
-#include <mruby/presym.h>
#include "node.h"
#define YYLEX_PARAM p
+#define mrbc_malloc(s) mrb_basic_alloc_func(NULL,(s))
+#define mrbc_realloc(p,s) mrb_basic_alloc_func((p),(s))
+#define mrbc_free(p) mrb_basic_alloc_func((p),0)
+
typedef mrb_ast_node node;
typedef struct mrb_parser_state parser_state;
typedef struct mrb_parser_heredoc_info parser_heredoc_info;
@@ -38,6 +42,15 @@ static void yywarning(parser_state *p, const char *s);
static void backref_error(parser_state *p, node *n);
static void void_expr_error(parser_state *p, node *n);
static void tokadd(parser_state *p, int32_t c);
+static const char* tok(parser_state *p);
+static int toklen(parser_state *p);
+
+/* Forward declarations for variable-sized simple node functions */
+
+/* Forward declarations for variable-sized advanced node functions */
+
+/* Helper function to check node type for both traditional and variable-sized nodes */
+static mrb_bool node_type_p(node *n, enum node_type type);
#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c))
@@ -58,19 +71,7 @@ typedef unsigned int stack_type;
#define CMDARG_LEXPOP() BITSTACK_LEXPOP(p->cmdarg_stack)
#define CMDARG_P() BITSTACK_SET_P(p->cmdarg_stack)
-#define SET_LINENO(c,n) ((c)->lineno = (n))
-#define NODE_LINENO(c,n) do {\
- if (n) {\
- (c)->filename_index = (n)->filename_index;\
- (c)->lineno = (n)->lineno;\
- }\
-} while (0)
-
-#define sym(x) ((mrb_sym)(intptr_t)(x))
-#define nsym(x) ((node*)(intptr_t)(x))
-#define nint(x) ((node*)(intptr_t)(x))
-#define intn(x) ((int)(intptr_t)(x))
-#define typen(x) ((enum node_type)(intptr_t)(x))
+#define SET_LINENO(c,n) (((struct mrb_ast_var_header*)(c))->lineno = (n))
#define NUM_SUFFIX_R (1<<0)
#define NUM_SUFFIX_I (1<<1)
@@ -89,7 +90,7 @@ intern_gen(parser_state *p, const char *s, size_t len)
}
#define intern(s,len) intern_gen(p,(s),(len))
-#define intern_op(op) MRB_OPSYM_2(p->mrb, op)
+#define intern_op(op) MRB_OPSYM(op)
static mrb_sym
intern_numparam_gen(parser_state *p, int num)
@@ -111,7 +112,7 @@ cons_free_gen(parser_state *p, node *cons)
static void*
parser_palloc(parser_state *p, size_t size)
{
- void *m = mrb_mempool_alloc(p->pool, size);
+ void *m = mempool_alloc(p->pool, size);
if (!m) {
MRB_THROW(p->mrb->jmp);
@@ -124,27 +125,50 @@ parser_palloc(parser_state *p, size_t size)
static node*
cons_gen(parser_state *p, node *car, node *cdr)
{
- node *c;
+ struct mrb_ast_node *c;
+ /* Try to reuse from free list first - only for 16-byte nodes */
if (p->cells) {
- c = p->cells;
+ c = (struct mrb_ast_node*)p->cells;
p->cells = p->cells->cdr;
}
else {
- c = (node*)parser_palloc(p, sizeof(mrb_ast_node));
+ c = (struct mrb_ast_node*)parser_palloc(p, sizeof(struct mrb_ast_node));
}
-
c->car = car;
c->cdr = cdr;
- c->lineno = p->lineno;
- c->filename_index = p->current_filename_index;
- /* beginning of next partial file; need to point the previous file */
+ /* Don't initialize location fields for structure nodes - saves CPU */
+ return (node*)c;
+}
+
+/* Head-only location optimization: separate functions for head vs structure nodes */
+#define cons(a,b) cons_gen(p,(a),(b)) /* Structure nodes - no location */
+/* Initialize variable node header */
+static void
+init_var_header(struct mrb_ast_var_header *header, parser_state *p, enum node_type type)
+{
+ header->lineno = p->lineno;
+ header->filename_index = p->current_filename_index;
+ header->node_type = (uint8_t)type;
+
+ /* Handle file boundary edge case */
if (p->lineno == 0 && p->current_filename_index > 0) {
- c->filename_index--;
+ header->filename_index--;
}
- return c;
}
-#define cons(a,b) cons_gen(p,(a),(b))
+
+/* Combined allocate + init header helper */
+static inline void*
+new_node(parser_state *p, size_t size, enum node_type type)
+{
+ void *n = parser_palloc(p, size);
+ init_var_header((struct mrb_ast_var_header*)n, p, type);
+ return n;
+}
+
+/* Type-safe macro wrapper for node allocation */
+#define NEW_NODE(type_name, node_type) \
+ (struct mrb_ast_##type_name##_node*)new_node(p, sizeof(struct mrb_ast_##type_name##_node), node_type)
static node*
list1_gen(parser_state *p, node *a)
@@ -156,39 +180,18 @@ list1_gen(parser_state *p, node *a)
static node*
list2_gen(parser_state *p, node *a, node *b)
{
- return cons(a, cons(b,0));
+ 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)));
+ 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;
@@ -284,7 +287,7 @@ local_var_p(parser_state *p, mrb_sym sym)
while (l) {
node *n = l->car;
while (n) {
- if (sym(n->car) == sym) return TRUE;
+ if (node_to_sym(n->car) == sym) return TRUE;
n = n->cdr;
}
l = l->cdr;
@@ -313,7 +316,7 @@ local_add_f(parser_state *p, mrb_sym sym)
if (p->locals) {
node *n = p->locals->car;
while (n) {
- if (sym(n->car) == sym) {
+ if (node_to_sym(n->car) == sym) {
mrb_int len;
const char* name = mrb_sym_name_len(p->mrb, sym, &len);
if (len > 0 && name[0] != '_') {
@@ -323,7 +326,7 @@ local_add_f(parser_state *p, mrb_sym sym)
}
n = n->cdr;
}
- p->locals->car = push(p->locals->car, nsym(sym));
+ p->locals->car = push(p->locals->car, sym_to_node(sym));
}
}
@@ -351,16 +354,47 @@ locals_node(parser_state *p)
return p->locals ? p->locals->car : NULL;
}
+/* Helper function to check node type for both traditional and variable-sized nodes */
+static mrb_bool
+node_type_p(node *n, enum node_type type)
+{
+ if (!n) return FALSE;
+
+ /* Check if this is a variable-sized node */
+ struct mrb_ast_var_header *header = (struct mrb_ast_var_header*)n;
+ return ((enum node_type)header->node_type == type);
+}
+
+/* Helper functions for variable-sized node detection */
+static enum node_type
+node_type(node *n)
+{
+ if (!n) return (enum node_type)0;
+
+ /* Try to interpret as variable-sized node */
+ struct mrb_ast_var_header *header = (struct mrb_ast_var_header*)n;
+ enum node_type type = (enum node_type)header->node_type;
+
+ /* Validate that the node type is within valid range for variable-sized nodes */
+ if (type >= NODE_SCOPE && type < NODE_LAST) {
+ return type;
+ }
+
+ /* If node type is invalid, this is likely a cons-list node */
+ /* Return a special sentinel value to indicate cons-list fallback */
+ return NODE_LAST; /* Use NODE_LAST as sentinel for cons-list nodes */
+}
+
static void
nvars_nest(parser_state *p)
{
- p->nvars = cons(nint(0), p->nvars);
+ p->nvars = cons(int_to_node(0), p->nvars);
}
static void
nvars_block(parser_state *p)
{
- p->nvars = cons(nint(-2), p->nvars);
+ p->nvars = cons(int_to_node(-2), p->nvars);
}
static void
@@ -369,30 +403,56 @@ nvars_unnest(parser_state *p)
p->nvars = p->nvars->cdr;
}
-/* (:scope (vars..) (prog...)) */
+/* struct: scope_node(locals, body) */
static node*
new_scope(parser_state *p, node *body)
{
- return cons((node*)NODE_SCOPE, cons(locals_node(p), body));
+ struct mrb_ast_scope_node *scope_node = NEW_NODE(scope, NODE_SCOPE);
+ scope_node->locals = locals_node(p);
+ scope_node->body = body;
+ return (node*)scope_node;
+}
+
+/* struct: stmts_node(stmts) - uses cons list */
+static node*
+new_stmts(parser_state *p, node *body)
+{
+ struct mrb_ast_stmts_node *n = NEW_NODE(stmts, NODE_STMTS);
+ n->stmts = body ? list1(body) : 0; /* Wrap single statement in cons-list */
+
+ return (node*)n;
}
-/* (:begin prog...) */
+/* Helper: push statement to stmts node */
+static node*
+stmts_push(parser_state *p, node *stmts, node *stmt)
+{
+ struct mrb_ast_stmts_node *n = stmts_node(stmts);
+ n->stmts = push(n->stmts, stmt);
+ return stmts;
+}
+
+/* struct: begin_node(body) */
static node*
new_begin(parser_state *p, node *body)
{
- if (body) {
- return list2((node*)NODE_BEGIN, body);
- }
- return cons((node*)NODE_BEGIN, 0);
+ struct mrb_ast_begin_node *begin_node = NEW_NODE(begin, NODE_BEGIN);
+ begin_node->body = body;
+ return (node*)begin_node;
}
#define newline_node(n) (n)
-/* (:rescue body rescue else) */
+/* struct: rescue_node(body, rescue_clauses, else_clause) */
static node*
new_rescue(parser_state *p, node *body, node *resq, node *els)
{
- return list4((node*)NODE_RESCUE, body, resq, els);
+ struct mrb_ast_rescue_node *n = NEW_NODE(rescue, NODE_RESCUE);
+ n->body = body;
+ n->rescue_clauses = resq;
+ n->else_clause = els;
+
+ return (node*)n;
}
static node*
@@ -401,312 +461,530 @@ new_mod_rescue(parser_state *p, node *body, node *resq)
return new_rescue(p, body, list1(list3(0, 0, resq)), 0);
}
-/* (:ensure body ensure) */
+/* struct: ensure_node(body, ensure_clause) */
static node*
new_ensure(parser_state *p, node *a, node *b)
{
- return cons((node*)NODE_ENSURE, cons(a, cons(0, b)));
+ struct mrb_ast_ensure_node *ensure_node = NEW_NODE(ensure, NODE_ENSURE);
+ ensure_node->body = a;
+ ensure_node->ensure_clause = b;
+ return (node*)ensure_node;
}
-/* (:nil) */
+/* struct: nil_node() */
static node*
new_nil(parser_state *p)
{
- return list1((node*)NODE_NIL);
+ struct mrb_ast_nil_node *n = NEW_NODE(nil, NODE_NIL);
+
+ return (node*)n;
}
-/* (:true) */
+/* struct: true_node() */
static node*
new_true(parser_state *p)
{
- return list1((node*)NODE_TRUE);
+ struct mrb_ast_true_node *n = NEW_NODE(true, NODE_TRUE);
+
+ return (node*)n;
}
-/* (:false) */
+/* struct: false_node() */
static node*
new_false(parser_state *p)
{
- return list1((node*)NODE_FALSE);
+ struct mrb_ast_false_node *n = NEW_NODE(false, NODE_FALSE);
+
+ return (node*)n;
}
-/* (:alias new old) */
+/* struct: alias_node(new_name, old_name) */
static node*
new_alias(parser_state *p, mrb_sym a, mrb_sym b)
{
- return cons((node*)NODE_ALIAS, cons(nsym(a), nsym(b)));
+ struct mrb_ast_alias_node *alias_node = NEW_NODE(alias, NODE_ALIAS);
+ alias_node->new_name = a;
+ alias_node->old_name = b;
+ return (node*)alias_node;
}
-/* (:if cond then else) */
+/* struct: if_node(cond, then_body, else_body) */
static node*
-new_if(parser_state *p, node *a, node *b, node *c)
+new_if(parser_state *p, node *condition, node *then_body, node *else_body)
{
- void_expr_error(p, a);
- return list4((node*)NODE_IF, a, b, c);
+ void_expr_error(p, condition);
+
+ struct mrb_ast_if_node *n = NEW_NODE(if, NODE_IF);
+ n->condition = condition;
+ n->then_body = then_body;
+ n->else_body = else_body;
+
+ return (node*)n;
}
-/* (:unless cond then else) */
+/* struct: while_node(cond, body) */
static node*
-new_unless(parser_state *p, node *a, node *b, node *c)
+new_while(parser_state *p, node *condition, node *body)
{
- void_expr_error(p, a);
- return list4((node*)NODE_IF, a, c, b);
+ void_expr_error(p, condition);
+
+ struct mrb_ast_while_node *n = NEW_NODE(while, NODE_WHILE);
+ n->condition = condition;
+ n->body = body;
+
+ return (node*)n;
}
-/* (:while cond body) */
+/* struct: until_node(cond, body) */
static node*
-new_while(parser_state *p, node *a, node *b)
+new_until(parser_state *p, node *condition, node *body)
{
- void_expr_error(p, a);
- return cons((node*)NODE_WHILE, cons(a, b));
+ void_expr_error(p, condition);
+
+ struct mrb_ast_until_node *n = NEW_NODE(until, NODE_UNTIL);
+ n->condition = condition;
+ n->body = body;
+
+ return (node*)n;
}
-/* (:until cond body) */
+/* struct: while_node(cond, body) */
static node*
-new_until(parser_state *p, node *a, node *b)
+new_while_mod(parser_state *p, node *condition, node *body)
{
- void_expr_error(p, a);
- return cons((node*)NODE_UNTIL, cons(a, b));
+ node *while_node = new_while(p, condition, body);
+ struct mrb_ast_while_node *n = (struct mrb_ast_while_node*)while_node;
+ n->header.node_type = NODE_WHILE_MOD;
+ return while_node;
+}
+
+/* struct: until_node(cond, body) */
+static node*
+new_until_mod(parser_state *p, node *a, node *b)
+{
+ node *until_node = new_until(p, a, b);
+ struct mrb_ast_until_node *n = (struct mrb_ast_until_node*)until_node;
+ n->header.node_type = NODE_UNTIL_MOD;
+ return until_node;
}
-/* (:for var obj body) */
+
+/* struct: for_node(var, obj, body) */
static node*
new_for(parser_state *p, node *v, node *o, node *b)
{
void_expr_error(p, o);
- return list4((node*)NODE_FOR, v, o, b);
+
+ struct mrb_ast_for_node *n = NEW_NODE(for, NODE_FOR);
+ n->var = v;
+ n->iterable = o;
+ n->body = b;
+
+ return (node*)n;
}
-/* (:case a ((when ...) body) ((when...) body)) */
+/* struct: case_node(expr, when_clauses) - uses cons list */
static node*
new_case(parser_state *p, node *a, node *b)
{
- node *n = list2((node*)NODE_CASE, a);
- node *n2 = n;
-
void_expr_error(p, a);
- while (n2->cdr) {
- n2 = n2->cdr;
+
+ struct mrb_ast_case_node *n = NEW_NODE(case, NODE_CASE);
+ n->value = a;
+ n->body = b;
+
+ return (node*)n;
+}
+
+/* Pattern matching case/in expression */
+static node*
+new_case_match(parser_state *p, node *val, node *in_clauses)
+{
+ void_expr_error(p, val);
+
+ struct mrb_ast_case_match_node *n = NEW_NODE(case_match, NODE_CASE_MATCH);
+ n->value = val;
+ n->in_clauses = in_clauses;
+
+ return (node*)n;
+}
+
+/* Create value pattern node */
+static node*
+new_pat_value(parser_state *p, node *val)
+{
+ struct mrb_ast_pat_value_node *n = NEW_NODE(pat_value, NODE_PAT_VALUE);
+ n->value = val;
+ return (node*)n;
+}
+
+/* Create variable pattern node */
+static node*
+new_pat_var(parser_state *p, mrb_sym name)
+{
+ struct mrb_ast_pat_var_node *n = NEW_NODE(pat_var, NODE_PAT_VAR);
+ n->name = name;
+ /* Register as local variable if not wildcard */
+ if (name) {
+ local_add(p, name);
}
- n2->cdr = b;
- return n;
+ return (node*)n;
}
-/* (:postexe a) */
+/* Create pin pattern node (^var) */
+static node*
+new_pat_pin(parser_state *p, mrb_sym name)
+{
+ struct mrb_ast_pat_pin_node *n = NEW_NODE(pat_pin, NODE_PAT_PIN);
+ n->name = name;
+ /* Pin operator references existing variable, does not create new binding */
+ return (node*)n;
+}
+
+/* Create as pattern node (pattern => var) */
+static node*
+new_pat_as(parser_state *p, node *pattern, mrb_sym name)
+{
+ struct mrb_ast_pat_as_node *n = NEW_NODE(pat_as, NODE_PAT_AS);
+ n->pattern = pattern;
+ n->name = name;
+ local_add(p, name);
+ return (node*)n;
+}
+
+/* Create alternative pattern node (pat1 | pat2) */
+static node*
+new_pat_alt(parser_state *p, node *left, node *right)
+{
+ struct mrb_ast_pat_alt_node *n = NEW_NODE(pat_alt, NODE_PAT_ALT);
+ n->left = left;
+ n->right = right;
+ return (node*)n;
+}
+
+/* Create array pattern node [a, b, *rest, c] */
+static node*
+new_pat_array(parser_state *p, node *pre, node *rest, node *post)
+{
+ struct mrb_ast_pat_array_node *n = NEW_NODE(pat_array, NODE_PAT_ARRAY);
+ n->pre = pre;
+ n->rest = rest;
+ n->post = post;
+ return (node*)n;
+}
+
+/* Create find pattern node [*pre, elems, *post] */
+static node*
+new_pat_find(parser_state *p, node *pre, node *elems, node *post)
+{
+ struct mrb_ast_pat_find_node *n = NEW_NODE(pat_find, NODE_PAT_FIND);
+ n->pre = pre;
+ n->elems = elems;
+ n->post = post;
+ return (node*)n;
+}
+
+/* Create hash pattern node {a:, b: x, **rest} */
+static node*
+new_pat_hash(parser_state *p, node *pairs, node *rest)
+{
+ struct mrb_ast_pat_hash_node *n = NEW_NODE(pat_hash, NODE_PAT_HASH);
+ n->pairs = pairs;
+ n->rest = rest;
+ return (node*)n;
+}
+
+/* Create one-line pattern matching node (expr in pattern / expr => pattern) */
+static node*
+new_match_pat(parser_state *p, node *value, node *pattern, mrb_bool raise_on_fail)
+{
+ struct mrb_ast_match_pat_node *n = NEW_NODE(match_pat, NODE_MATCH_PAT);
+ n->value = value;
+ n->pattern = pattern;
+ n->raise_on_fail = raise_on_fail;
+ return (node*)n;
+}
+
+/* Create in-clause node for case/in */
+static node*
+new_in(parser_state *p, node *pattern, node *guard, node *body, mrb_bool guard_is_unless)
+{
+ struct mrb_ast_in_node *n = NEW_NODE(in, NODE_IN);
+ n->pattern = pattern;
+ n->guard = guard;
+ n->body = body;
+ n->guard_is_unless = guard_is_unless;
+ return (node*)n;
+}
+
+/* struct: postexe_node(body) */
static node*
new_postexe(parser_state *p, node *a)
{
- return cons((node*)NODE_POSTEXE, a);
+ struct mrb_ast_postexe_node *postexe_node = NEW_NODE(postexe, NODE_POSTEXE);
+ postexe_node->body = a;
+ return (node*)postexe_node;
}
-/* (:self) */
+/* struct: self_node() */
static node*
new_self(parser_state *p)
{
- return list1((node*)NODE_SELF);
+ struct mrb_ast_self_node *n = NEW_NODE(self, NODE_SELF);
+
+ return (node*)n;
}
-/* (:call a b c) */
+/* struct: call_node(receiver, method, args) */
static node*
-new_call(parser_state *p, node *a, mrb_sym b, node *c, int pass)
+new_call(parser_state *p, node *receiver, mrb_sym method, node *args, int pass)
{
- node *n = list4(nint(pass?NODE_CALL:NODE_SCALL), a, nsym(b), c);
- void_expr_error(p, a);
- NODE_LINENO(n, a);
- return n;
+ /* Calculate size needed (fixed size now) */ struct mrb_ast_call_node *n = NEW_NODE(call, NODE_CALL);
+ n->receiver = receiver;
+ n->method_name = method;
+ n->safe_call = (pass == 0); /* pass == 0 means safe call (&.) */
+
+ /* Store args pointer directly - no need to unpack and repack */
+ n->args = args;
+
+ void_expr_error(p, receiver);
+ return (node*)n;
}
-/* (:fcall self mid args) */
+/* struct: fcall_node(method, args) */
static node*
new_fcall(parser_state *p, mrb_sym b, node *c)
{
- node *n = list4((node*)NODE_FCALL, 0, nsym(b), c);
- NODE_LINENO(n, c);
- return n;
+ return new_call(p, NULL, b, c, '.');
}
/* (a b . c) */
static node*
new_callargs(parser_state *p, node *a, node *b, node *c)
{
- return cons(a, cons(b, c));
+ /* Allocate struct mrb_ast_callargs (fixed size, like new_args) */
+ struct mrb_ast_callargs *callargs = (struct mrb_ast_callargs*)parser_palloc(p, sizeof(struct mrb_ast_callargs));
+
+ /* Initialize members directly */
+ callargs->regular_args = a; /* Cons list of regular arguments (preserves splat compatibility) */
+ callargs->keyword_args = b; /* Keyword arguments hash node */
+ callargs->block_arg = c; /* Block argument node */
+
+ /* Return direct cast to node (like new_args) */
+ return (node*)callargs;
}
-/* (:super . c) */
+/* struct: super_node(args) */
static node*
new_super(parser_state *p, node *c)
{
- return cons((node*)NODE_SUPER, c);
+ struct mrb_ast_super_node *n = NEW_NODE(super, NODE_SUPER);
+ n->args = c;
+
+ return (node*)n;
}
-/* (:zsuper) */
+/* struct: zsuper_node() */
static node*
new_zsuper(parser_state *p)
{
- return cons((node*)NODE_ZSUPER, 0);
+ struct mrb_ast_super_node *n = NEW_NODE(super, NODE_ZSUPER);
+ n->args = NULL; /* zsuper initially has no args, but may be added by call_with_block */
+ return (node*)n;
}
-/* (:yield . c) */
+/* struct: yield_node(args) */
static node*
new_yield(parser_state *p, node *c)
{
- if (c && c->cdr && c->cdr->cdr) {
- yyerror(NULL, p, "both block arg and actual block given");
- }
+ /* Handle callargs structure - direct casting like new_args() */
+ if (c) {
+ struct mrb_ast_callargs *callargs = (struct mrb_ast_callargs*)c;
+ if (callargs->block_arg) {
+ yyerror(NULL, p, "both block arg and actual block given");
+ }
+ } struct mrb_ast_yield_node *n = NEW_NODE(yield, NODE_YIELD);
+ n->args = c;
- return cons((node*)NODE_YIELD, c);
+ return (node*)n;
}
-/* (:return . c) */
+/* struct: return_node(value) */
static node*
new_return(parser_state *p, node *c)
{
- return cons((node*)NODE_RETURN, c);
+ struct mrb_ast_return_node *n = NEW_NODE(return, NODE_RETURN);
+ n->args = c;
+
+ return (node*)n;
}
-/* (:break . c) */
+/* struct: break_node(value) */
static node*
new_break(parser_state *p, node *c)
{
- return cons((node*)NODE_BREAK, c);
+ struct mrb_ast_break_node *n = NEW_NODE(break, NODE_BREAK);
+ n->value = c;
+ return (node*)n;
}
-/* (:next . c) */
+/* struct: next_node(value) */
static node*
new_next(parser_state *p, node *c)
{
- return cons((node*)NODE_NEXT, c);
+ struct mrb_ast_next_node *n = NEW_NODE(next, NODE_NEXT);
+ n->value = c;
+ return (node*)n;
}
-/* (:redo) */
+/* struct: redo_node() */
static node*
new_redo(parser_state *p)
{
- return list1((node*)NODE_REDO);
+ struct mrb_ast_redo_node *n = NEW_NODE(redo, NODE_REDO);
+ return (node*)n;
}
-/* (:retry) */
+/* struct: retry_node() */
static node*
new_retry(parser_state *p)
{
- return list1((node*)NODE_RETRY);
+ struct mrb_ast_retry_node *n = NEW_NODE(retry, NODE_RETRY);
+ return (node*)n;
}
-/* (:dot2 a b) */
+/* struct: dot2_node(beg, end) */
static node*
new_dot2(parser_state *p, node *a, node *b)
{
- return cons((node*)NODE_DOT2, cons(a, b));
+ struct mrb_ast_dot2_node *n = NEW_NODE(dot2, NODE_DOT2);
+ n->left = a;
+ n->right = b;
+
+ return (node*)n;
}
-/* (:dot3 a b) */
+/* struct: dot3_node(beg, end) */
static node*
new_dot3(parser_state *p, node *a, node *b)
{
- return cons((node*)NODE_DOT3, cons(a, b));
+ struct mrb_ast_dot3_node *n = NEW_NODE(dot3, NODE_DOT3);
+ n->left = a;
+ n->right = b;
+
+ return (node*)n;
}
-/* (:colon2 b c) */
+/* struct: colon2_node(base, name) */
static node*
new_colon2(parser_state *p, node *b, mrb_sym c)
{
void_expr_error(p, b);
- return cons((node*)NODE_COLON2, cons(b, nsym(c)));
+
+ struct mrb_ast_colon2_node *colon2_node = NEW_NODE(colon2, NODE_COLON2);
+ colon2_node->base = b;
+ colon2_node->name = c;
+ return (node*)colon2_node;
}
-/* (:colon3 . c) */
+/* struct: colon3_node(name) */
static node*
new_colon3(parser_state *p, mrb_sym c)
{
- return cons((node*)NODE_COLON3, nsym(c));
+ struct mrb_ast_colon3_node *colon3_node = NEW_NODE(colon3, NODE_COLON3);
+ colon3_node->name = c;
+ return (node*)colon3_node;
}
-/* (:and a b) */
+/* struct: and_node(left, right) */
static node*
new_and(parser_state *p, node *a, node *b)
{
void_expr_error(p, a);
- return cons((node*)NODE_AND, cons(a, b));
+
+ struct mrb_ast_and_node *n = NEW_NODE(and, NODE_AND);
+ n->left = a;
+ n->right = b;
+
+ return (node*)n;
}
-/* (:or a b) */
+/* struct: or_node(left, right) */
static node*
new_or(parser_state *p, node *a, node *b)
{
void_expr_error(p, a);
- return cons((node*)NODE_OR, cons(a, b));
+
+ struct mrb_ast_or_node *n = NEW_NODE(or, NODE_OR);
+ n->left = a;
+ n->right = b;
+
+ return (node*)n;
}
-/* (:array a...) */
+/* struct: array_node(elements) - uses cons list */
static node*
new_array(parser_state *p, node *a)
{
- return cons((node*)NODE_ARRAY, a);
+ struct mrb_ast_array_node *n = NEW_NODE(array, NODE_ARRAY);
+ n->elements = a;
+
+ return (node*)n;
}
-/* (:splat . a) */
+/* struct: splat_node(value) */
static node*
new_splat(parser_state *p, node *a)
{
void_expr_error(p, a);
- return cons((node*)NODE_SPLAT, a);
+
+ struct mrb_ast_splat_node *splat_node = NEW_NODE(splat, NODE_SPLAT);
+ splat_node->value = a;
+ return (node*)splat_node;
}
-/* (:hash (k . v) (k . v)...) */
+/* struct: hash_node(pairs) - uses cons list */
static node*
new_hash(parser_state *p, node *a)
{
- return cons((node*)NODE_HASH, a);
-}
+ struct mrb_ast_hash_node *n = NEW_NODE(hash, NODE_HASH);
+ n->pairs = a;
-/* (:kw_hash (k . v) (k . v)...) */
-static node*
-new_kw_hash(parser_state *p, node *a)
-{
- return cons((node*)NODE_KW_HASH, a);
+ return (node*)n;
}
/* (:sym . a) */
+/* Symbol node creation - supports both variable and legacy modes */
static node*
new_sym(parser_state *p, mrb_sym sym)
{
- return cons((node*)NODE_SYM, nsym(sym));
-}
+ struct mrb_ast_sym_node *n = NEW_NODE(sym, NODE_SYM);
+ n->symbol = sym;
-static mrb_sym
-new_strsym(parser_state *p, node* str)
-{
- const char *s = (const char*)str->cdr->car;
- size_t len = (size_t)str->cdr->cdr;
-
- return mrb_intern(p->mrb, s, len);
+ return (node*)n;
}
-/* (:lvar . a) */
static node*
-new_lvar(parser_state *p, mrb_sym sym)
+new_xvar(parser_state *p, mrb_sym sym, enum node_type type)
{
- return cons((node*)NODE_LVAR, nsym(sym));
-}
+ struct mrb_ast_var_node *n = NEW_NODE(var, type);
+ n->symbol = sym;
-/* (:gvar . a) */
-static node*
-new_gvar(parser_state *p, mrb_sym sym)
-{
- return cons((node*)NODE_GVAR, nsym(sym));
+ return (node*)n;
}
-/* (:ivar . a) */
-static node*
-new_ivar(parser_state *p, mrb_sym sym)
-{
- return cons((node*)NODE_IVAR, nsym(sym));
-}
+#define new_lvar(p, sym) new_xvar(p, sym, NODE_LVAR)
+#define new_ivar(p, sym) new_xvar(p, sym, NODE_IVAR)
+#define new_gvar(p, sym) new_xvar(p, sym, NODE_GVAR)
+#define new_cvar(p, sym) new_xvar(p, sym, NODE_CVAR)
-/* (:cvar . a) */
-static node*
-new_cvar(parser_state *p, mrb_sym sym)
+static mrb_sym
+new_strsym(parser_state *p, node* str)
{
- return cons((node*)NODE_CVAR, nsym(sym));
+ size_t len = (size_t)str->car;
+ const char *s = (const char*)str->cdr;
+
+ return mrb_intern(p->mrb, s, len);
}
/* (:nvar . a) */
@@ -716,132 +994,162 @@ new_nvar(parser_state *p, int num)
int nvar;
node *nvars = p->nvars->cdr;
while (nvars) {
- nvar = intn(nvars->car);
+ nvar = node_to_int(nvars->car);
if (nvar == -2) break; /* top of the scope */
if (nvar > 0) {
yyerror(NULL, p, "numbered parameter used in outer block");
break;
}
- nvars->car = nint(-1);
+ nvars->car = int_to_node(-1);
nvars = nvars->cdr;
}
- nvar = intn(p->nvars->car);
+ nvar = node_to_int(p->nvars->car);
if (nvar == -1) {
yyerror(NULL, p, "numbered parameter used in inner block");
}
else {
- p->nvars->car = nint(nvar > num ? nvar : num);
+ p->nvars->car = int_to_node(nvar > num ? nvar : num);
}
- return cons((node*)NODE_NVAR, nint(num));
+ struct mrb_ast_nvar_node *n = NEW_NODE(nvar, NODE_NVAR);
+ n->num = num;
+ return (node*)n;
}
-/* (:const . a) */
+/* struct: const_node(name) */
static node*
new_const(parser_state *p, mrb_sym sym)
{
- return cons((node*)NODE_CONST, nsym(sym));
+ struct mrb_ast_const_node *n = NEW_NODE(const, NODE_CONST);
+ n->symbol = sym;
+
+ return (node*)n;
}
-/* (:undef a...) */
+/* struct: undef_node(syms) - uses cons list */
static node*
-new_undef(parser_state *p, mrb_sym sym)
+new_undef(parser_state *p, node *syms)
{
- return list2((node*)NODE_UNDEF, nsym(sym));
+ struct mrb_ast_undef_node *undef_node = NEW_NODE(undef, NODE_UNDEF);
+ undef_node->syms = syms;
+ return (node*)undef_node;
}
-/* (:class class super body) */
+/* struct: class_node(path, super, body) */
static node*
new_class(parser_state *p, node *c, node *s, node *b)
{
void_expr_error(p, s);
- return list4((node*)NODE_CLASS, c, s, cons(locals_node(p), b));
+
+ struct mrb_ast_class_node *n = NEW_NODE(class, NODE_CLASS);
+ n->name = c;
+ n->superclass = s;
+ n->body = cons(locals_node(p), b);
+
+ return (node*)n;
}
-/* (:sclass obj body) */
+/* struct: sclass_node(obj, body) */
static node*
new_sclass(parser_state *p, node *o, node *b)
{
void_expr_error(p, o);
- return list3((node*)NODE_SCLASS, o, cons(locals_node(p), b));
+
+ struct mrb_ast_sclass_node *n = NEW_NODE(sclass, NODE_SCLASS);
+ n->obj = o;
+ n->body = cons(locals_node(p), b);
+
+ return (node*)n;
}
-/* (:module module body) */
+/* struct: module_node(path, body) */
static node*
new_module(parser_state *p, node *m, node *b)
{
- return list3((node*)NODE_MODULE, m, cons(locals_node(p), b));
+ struct mrb_ast_module_node *n = NEW_NODE(module, NODE_MODULE);
+ n->name = m;
+ n->body = cons(locals_node(p), b);
+
+ return (node*)n;
}
-/* (:def m lv (arg . body)) */
+/* struct: def_node(name, args, body) */
static node*
-new_def(parser_state *p, mrb_sym m, node *a, node *b)
+new_def(parser_state *p, mrb_sym name)
{
- return list5((node*)NODE_DEF, nsym(m), 0, a, b);
+ struct mrb_ast_def_node *n = NEW_NODE(def, NODE_DEF);
+ n->name = name;
+ n->args = (struct mrb_ast_args *)int_to_node(p->cmdarg_stack);
+ n->locals = local_switch(p);
+ n->body = NULL;
+
+ return (node*)n;
}
static void
defn_setup(parser_state *p, node *d, node *a, node *b)
{
- node *n = d->cdr->cdr;
+ struct mrb_ast_def_node *n = def_node(d);
+ node *locals = n->locals;
- n->car = locals_node(p);
- p->cmdarg_stack = intn(n->cdr->car);
- n->cdr->car = a;
- local_resume(p, n->cdr->cdr->car);
- n->cdr->cdr->car = b;
+ n->locals = locals_node(p);
+ p->cmdarg_stack = node_to_int(n->args);
+ n->args = (struct mrb_ast_args *)a;
+ n->body = b;
+ local_resume(p, locals);
}
-/* (:sdef obj m lv (arg . body)) */
+/* struct: sdef_node(obj, name, args, body) */
static node*
-new_sdef(parser_state *p, node *o, mrb_sym m, node *a, node *b)
+new_sdef(parser_state *p, node *o, mrb_sym name)
{
void_expr_error(p, o);
- return list6((node*)NODE_SDEF, o, nsym(m), 0, a, b);
-}
-static void
-defs_setup(parser_state *p, node *d, node *a, node *b)
-{
- node *n = d->cdr->cdr->cdr;
-
- n->car = locals_node(p);
- p->cmdarg_stack = intn(n->cdr->car);
- n->cdr->car = a;
- local_resume(p, n->cdr->cdr->car);
- n->cdr->cdr->car = b;
-}
-
-/* (:arg . sym) */
-static node*
-new_arg(parser_state *p, mrb_sym sym)
-{
- return cons((node*)NODE_ARG, nsym(sym));
+ struct mrb_ast_sdef_node *sdef_node = NEW_NODE(sdef, NODE_SDEF);
+ sdef_node->obj = o;
+ sdef_node->name = name;
+ sdef_node->args = (struct mrb_ast_args *)int_to_node(p->cmdarg_stack);
+ sdef_node->locals = local_switch(p);
+ sdef_node->body = NULL;
+ return (node*)sdef_node;
}
static void
local_add_margs(parser_state *p, node *n)
{
while (n) {
- if (typen(n->car->car) == NODE_MASGN) {
- node *t = n->car->cdr->cdr;
+ if (node_type(n->car) == NODE_MARG) {
+ struct mrb_ast_masgn_node *masgn_n = (struct mrb_ast_masgn_node*)n->car;
+ node *rhs = masgn_n->rhs;
+
+ /* For parameter destructuring, rhs contains the locals */
+ if (rhs) {
+ node *t = rhs;
+ while (t) {
+ local_add_f(p, node_to_sym(t->car));
+ t = t->cdr;
+ }
+ /* Clear cons list RHS immediately after use */
+ masgn_n->rhs = NULL;
+ }
- n->car->cdr->cdr = NULL;
- while (t) {
- local_add_f(p, sym(t->car));
- t = t->cdr;
+ /* Process nested destructuring in lhs components */
+ if (masgn_n->pre) {
+ local_add_margs(p, masgn_n->pre);
+ }
+ if (masgn_n->post) {
+ local_add_margs(p, masgn_n->post);
}
- local_add_margs(p, n->car->cdr->car->car);
- local_add_margs(p, n->car->cdr->car->cdr->cdr->car);
}
n = n->cdr;
}
}
+
static void
local_add_lv(parser_state *p, node *lv)
{
while (lv) {
- local_add_f(p, sym(lv->car));
+ local_add_f(p, node_to_sym(lv->car));
lv = lv->cdr;
}
}
@@ -855,66 +1163,91 @@ local_add_lv(parser_state *p, node *lv)
static node*
new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, node *tail)
{
- node *n;
-
local_add_margs(p, m);
local_add_margs(p, m2);
- n = cons(m2, tail);
- n = cons(nsym(rest), n);
- n = cons(opt, n);
+
+ /* Save original optional arguments before processing */
+ node *orig_opt = opt;
+
+ /* Process optional arguments (keep original side effects) */
while (opt) {
/* opt: (sym . (opt . lv)) -> (sym . opt) */
local_add_lv(p, opt->car->cdr->cdr);
opt->car->cdr = opt->car->cdr->car;
opt = opt->cdr;
}
- return cons(m, n);
+
+ /* Allocate struct mrb_ast_args (no hdr) */
+ struct mrb_ast_args *args = (struct mrb_ast_args*)parser_palloc(p, sizeof(struct mrb_ast_args));
+
+ /* Initialize members */
+ args->mandatory_args = m;
+ args->optional_args = orig_opt;
+ args->rest_arg = rest;
+ args->post_mandatory_args = m2;
+
+ /* Deconstruct tail cons list: (kws . (kwrest . blk)) */
+ if (tail) {
+ args->keyword_args = (node*)tail->car; /* kws */
+ args->kwrest_arg = (mrb_sym)(intptr_t)tail->cdr->car; /* kwrest */
+ args->block_arg = (mrb_sym)(intptr_t)tail->cdr->cdr; /* blk */
+ cons_free(tail->cdr);
+ cons_free(tail);
+ }
+ else {
+ args->keyword_args = NULL;
+ args->kwrest_arg = 0;
+ args->block_arg = 0;
+ }
+
+ return (node*)args;
}
-/* (:args_tail keywords rest_keywords_sym block_sym) */
+/* struct: args_tail_node(kwargs, kwrest, block) */
static node*
-new_args_tail(parser_state *p, node *kws, node *kwrest, mrb_sym blk)
+new_args_tail(parser_state *p, node *kws, mrb_sym kwrest, mrb_sym blk)
{
node *k;
if (kws || kwrest) {
- local_add_kw(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : 0);
+ local_add_kw(p, kwrest);
}
local_add_blk(p);
- if (blk) local_add_f(p, blk);
+ if (blk && blk != MRB_SYM(nil)) local_add_f(p, blk);
/* allocate register for keywords arguments */
/* order is for Proc#parameters */
for (k = kws; k; k = k->cdr) {
- if (!k->car->cdr->cdr->car) { /* allocate required keywords */
- local_add_f(p, sym(k->car->cdr->car));
+ if (!k->car->cdr) { /* allocate required keywords - simplified structure: (key . NULL) */
+ local_add_f(p, node_to_sym(k->car->car));
}
}
for (k = kws; k; k = k->cdr) {
- if (k->car->cdr->cdr->car) { /* allocate keywords with default */
- local_add_lv(p, k->car->cdr->cdr->car->cdr);
- k->car->cdr->cdr->car = k->car->cdr->cdr->car->car;
- local_add_f(p, sym(k->car->cdr->car));
+ if (k->car->cdr) { /* allocate keywords with default - simplified structure: (key . value) */
+ local_add_lv(p, k->car->cdr->cdr); /* value->cdr for default args */
+ k->car->cdr = k->car->cdr->car; /* value->car for default args */
+ local_add_f(p, node_to_sym(k->car->car));
}
}
- return list4((node*)NODE_ARGS_TAIL, kws, kwrest, nsym(blk));
+ /* Return cons list: (keyword . (kwrest . blk)) */
+ return cons(kws, cons(sym_to_node(kwrest), sym_to_node(blk)));
}
-/* (:kw_arg kw_sym def_arg) */
+/* (kw_sym . def_arg) - simplified from NODE_KW_ARG wrapper */
static node*
new_kw_arg(parser_state *p, mrb_sym kw, node *def_arg)
{
mrb_assert(kw);
- return list3((node*)NODE_KW_ARG, nsym(kw), def_arg);
+ return cons(sym_to_node(kw), def_arg);
}
/* (:kw_rest_args . a) */
static node*
new_kw_rest_args(parser_state *p, mrb_sym sym)
{
- return cons((node*)NODE_KW_REST_ARGS, nsym(sym));
+ return sym_to_node(intern_op(pow)); /* Use ** symbol as direct marker */
}
static node*
@@ -924,26 +1257,29 @@ new_args_dots(parser_state *p, node *m)
mrb_sym k = intern_op(pow);
mrb_sym b = intern_op(and);
local_add_f(p, r);
- return new_args(p, m, 0, r, 0,
- new_args_tail(p, 0, new_kw_rest_args(p, k), b));
+ return new_args(p, m, 0, r, 0, new_args_tail(p, NULL, k, b));
}
-/* (:block_arg . a) */
+/* struct: block_arg_node(value) */
static node*
new_block_arg(parser_state *p, node *a)
{
- return cons((node*)NODE_BLOCK_ARG, a);
+ struct mrb_ast_block_arg_node *block_arg_node = NEW_NODE(block_arg, NODE_BLOCK_ARG);
+ block_arg_node->value = a;
+ return (node*)block_arg_node;
}
static node*
setup_numparams(parser_state *p, node *a)
{
- int nvars = intn(p->nvars->car);
+ int nvars = node_to_int(p->nvars->car);
if (nvars > 0) {
int i;
mrb_sym sym;
- // m || opt || rest || tail
- if (a && (a->car || (a->cdr && a->cdr->car) || (a->cdr->cdr && a->cdr->cdr->car) || (a->cdr->cdr->cdr->cdr && a->cdr->cdr->cdr->cdr->car))) {
+ // Check if any arguments are already defined
+ struct mrb_ast_args *args = (struct mrb_ast_args *)a;
+ if (a && (args->mandatory_args || args->optional_args || args->rest_arg ||
+ args->post_mandatory_args || args->keyword_args || args->kwrest_arg)) {
yyerror(NULL, p, "ordinary parameter is defined");
}
else if (p->locals) {
@@ -956,8 +1292,8 @@ setup_numparams(parser_state *p, node *a)
buf[1] = i+'0';
buf[2] = '\0';
sym = intern_cstr(buf);
- args = cons(new_arg(p, sym), args);
- p->locals->car = cons(nsym(sym), p->locals->car);
+ args = cons(new_lvar(p, sym), args);
+ p->locals->car = cons(sym_to_node(sym), p->locals->car);
}
a = new_args(p, args, 0, 0, 0, 0);
}
@@ -965,86 +1301,243 @@ setup_numparams(parser_state *p, node *a)
return a;
}
-/* (:block arg body) */
+/* struct: block_node(args, body) */
static node*
new_block(parser_state *p, node *a, node *b)
{
- a = setup_numparams(p, a);
- return list4((node*)NODE_BLOCK, locals_node(p), a, b);
+ a = setup_numparams(p, a); struct mrb_ast_block_node *n = NEW_NODE(block, NODE_BLOCK);
+ n->locals = locals_node(p);
+ n->args = (struct mrb_ast_args *)a;
+ n->body = b;
+
+ return (node*)n;
}
-/* (:lambda arg body) */
+/* struct: lambda_node(args, body) */
static node*
new_lambda(parser_state *p, node *a, node *b)
{
- a = setup_numparams(p, a);
- return list4((node*)NODE_LAMBDA, locals_node(p), a, b);
+ a = setup_numparams(p, a); struct mrb_ast_lambda_node *lambda_node = NEW_NODE(lambda, NODE_LAMBDA);
+ lambda_node->locals = locals_node(p);
+ lambda_node->args = (struct mrb_ast_args *)a;
+ lambda_node->body = b;
+ return (node*)lambda_node;
}
-/* (:asgn lhs rhs) */
+/* struct: asgn_node(lhs, rhs) */
static node*
new_asgn(parser_state *p, node *a, node *b)
{
void_expr_error(p, b);
- return cons((node*)NODE_ASGN, cons(a, b));
+
+ struct mrb_ast_asgn_node *n = NEW_NODE(asgn, NODE_ASGN);
+ n->lhs = a;
+ n->rhs = b;
+
+ return (node*)n;
}
-/* (:masgn mlhs=(pre rest post) mrhs) */
+/* Helper function to create MASGN/MARG nodes */
+static node*
+new_masgn_helper(parser_state *p, node *a, node *b, enum node_type node_type)
+{
+ struct mrb_ast_masgn_node *n = NEW_NODE(masgn, node_type);
+
+ /* Extract pre, rest, post from cons list structure (a b c) */
+ if (a) {
+ n->pre = a->car; /* Pre-splat variables */
+ if (a->cdr) {
+ n->rest = a->cdr->car; /* Splat variable (or -1 for anonymous) */
+ if (a->cdr->cdr) {
+ n->post = a->cdr->cdr->car; /* Post-splat variables */
+ cons_free(a->cdr->cdr);
+ }
+ else {
+ n->post = NULL;
+ }
+ cons_free(a->cdr);
+ }
+ else {
+ n->rest = NULL;
+ n->post = NULL;
+ }
+ cons_free(a);
+ }
+ else {
+ n->pre = NULL;
+ n->rest = NULL;
+ n->post = NULL;
+ }
+ n->rhs = b;
+
+ return (node*)n;
+}
+
+/* struct: masgn_node(lhs, rhs) */
static node*
new_masgn(parser_state *p, node *a, node *b)
{
void_expr_error(p, b);
- return cons((node*)NODE_MASGN, cons(a, b));
+ return new_masgn_helper(p, a, b, NODE_MASGN);
}
-/* (:masgn mlhs mrhs) no check */
+/* (:marg mlhs mrhs) no check - for parameter destructuring */
static node*
-new_masgn_param(parser_state *p, node *a, node *b)
+new_marg(parser_state *p, node *a)
{
- return cons((node*)NODE_MASGN, cons(a, b));
+ return new_masgn_helper(p, a, p->locals->car, NODE_MARG);
}
-/* (:asgn lhs rhs) */
+/* struct: op_asgn_node(lhs, op, rhs) */
static node*
new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b)
{
void_expr_error(p, b);
- return list4((node*)NODE_OP_ASGN, a, nsym(op), b);
+
+ struct mrb_ast_op_asgn_node *n = NEW_NODE(op_asgn, NODE_OP_ASGN);
+ n->lhs = a;
+ n->op = op;
+ n->rhs = b;
+ return (node*)n;
+}
+
+static node*
+new_int_n(parser_state *p, int32_t val)
+{
+ struct mrb_ast_int_node *n = NEW_NODE(int, NODE_INT);
+ n->value = val;
+
+ return (node*)n;
}
static node*
new_imaginary(parser_state *p, node *imaginary)
{
- return new_fcall(p, MRB_SYM_2(p->mrb, Complex),
- new_callargs(p, list2(list3((node*)NODE_INT, (node*)strdup("0"), nint(10)), imaginary), 0, 0));
+ return new_fcall(p, MRB_SYM(Complex),
+ new_callargs(p, list2(new_int_n(p, 0), imaginary), 0, 0));
}
static node*
new_rational(parser_state *p, node *rational)
{
- return new_fcall(p, MRB_SYM_2(p->mrb, Rational), new_callargs(p, list1(rational), 0, 0));
+ return new_fcall(p, MRB_SYM(Rational), new_callargs(p, list1(rational), 0, 0));
+}
+
+/* Read integer into int32_t with overflow detection */
+static mrb_bool
+read_int32(const char *p, int base, int32_t *result)
+{
+ const char *e = p + strlen(p);
+ int32_t value = 0;
+ mrb_bool neg = FALSE;
+
+ if (base < 2 || base > 16) {
+ return FALSE;
+ }
+
+ if (*p == '+') {
+ p++;
+ }
+ else if (*p == '-') {
+ neg = TRUE;
+ p++;
+ }
+
+ while (p < e) {
+ int n;
+ char c = *p;
+
+ /* Skip underscores */
+ if (c == '_') {
+ p++;
+ continue;
+ }
+
+ /* Parse digit */
+ if (c >= '0' && c <= '9') {
+ n = c - '0';
+ }
+ else if (c >= 'a' && c <= 'f') {
+ n = c - 'a' + 10;
+ }
+ else if (c >= 'A' && c <= 'F') {
+ n = c - 'A' + 10;
+ }
+ else {
+ /* Invalid character */
+ return FALSE;
+ }
+
+ if (n >= base) {
+ /* Digit not valid for this base */
+ return FALSE;
+ }
+
+ /* Check for multiplication overflow */
+ if (value > INT32_MAX / base) {
+ return FALSE;
+ }
+
+ value *= base;
+
+ /* Check for addition overflow */
+ if (value > INT32_MAX - n) {
+ /* Special case: -INT32_MIN is valid */
+ if (neg && value == (INT32_MAX - n + 1) && p + 1 == e) {
+ *result = INT32_MIN;
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ value += n;
+ p++;
+ }
+
+ *result = neg ? -value : value;
+ return TRUE;
}
-/* (:int . i) */
static node*
new_int(parser_state *p, const char *s, int base, int suffix)
{
- node* result = list3((node*)NODE_INT, (node*)strdup(s), nint(base));
+ int32_t val;
+ node* result;
+
+ /* Try to parse as int32_t first */
+ if (read_int32(s, base, &val)) {
+ result = new_int_n(p, val);
+ }
+ else {
+ /* Big integer - create NODE_BIGINT */
+ struct mrb_ast_bigint_node *n = NEW_NODE(bigint, NODE_BIGINT);
+ n->string = strdup(s);
+ n->base = base;
+
+ result = (node*)n;
+ }
+
+ /* Handle suffix modifiers */
if (suffix & NUM_SUFFIX_R) {
result = new_rational(p, result);
}
if (suffix & NUM_SUFFIX_I) {
result = new_imaginary(p, result);
}
+
return result;
}
#ifndef MRB_NO_FLOAT
-/* (:float . i) */
+/* struct: float_node(value) */
static node*
new_float(parser_state *p, const char *s, int suffix)
{
- node* result = cons((node*)NODE_FLOAT, (node*)strdup(s));
+ struct mrb_ast_float_node *n = NEW_NODE(float, NODE_FLOAT);
+ n->value = strdup(s);
+
+ node* result = (node*)n;
+
if (suffix & NUM_SUFFIX_R) {
result = new_rational(p, result);
}
@@ -1055,180 +1548,135 @@ new_float(parser_state *p, const char *s, int suffix)
}
#endif
-/* (:str . (s . len)) */
-static node*
-new_str(parser_state *p, const char *s, size_t len)
-{
- return cons((node*)NODE_STR, cons((node*)strndup(s, len), nint(len)));
-}
-
-/* (:dstr . a) */
+/* Create string node from cons list */
+/* struct: str_node(str) */
static node*
-new_dstr(parser_state *p, node *a)
+new_str(parser_state *p, node *a)
{
- return cons((node*)NODE_DSTR, a);
-}
+ struct mrb_ast_str_node *n = NEW_NODE(str, NODE_STR);
+ n->list = a;
-static int
-string_node_p(node *n)
-{
- return (int)(typen(n->car) == NODE_STR);
+ return (node*)n;
}
+/* struct: xstr_node(str) */
static node*
-composite_string_node(parser_state *p, node *a, node *b)
-{
- size_t newlen = (size_t)a->cdr + (size_t)b->cdr;
- char *str = (char*)mrb_mempool_realloc(p->pool, a->car, (size_t)a->cdr + 1, newlen + 1);
- memcpy(str + (size_t)a->cdr, b->car, (size_t)b->cdr);
- str[newlen] = '\0';
- a->car = (node*)str;
- a->cdr = (node*)newlen;
- cons_free(b);
- return a;
-}
-
-static node*
-concat_string(parser_state *p, node *a, node *b)
+new_xstr(parser_state *p, node *a)
{
- if (string_node_p(a)) {
- if (string_node_p(b)) {
- /* a == NODE_STR && b == NODE_STR */
- composite_string_node(p, a->cdr, b->cdr);
- cons_free(b);
- return a;
- }
- else {
- /* a == NODE_STR && b == NODE_DSTR */
-
- if (string_node_p(b->cdr->car)) {
- /* a == NODE_STR && b->[NODE_STR, ...] */
- composite_string_node(p, a->cdr, b->cdr->car->cdr);
- cons_free(b->cdr->car);
- b->cdr->car = a;
- return b;
- }
- }
- }
- else {
- node *c; /* last node of a */
- for (c = a; c->cdr != NULL; c = c->cdr)
- ;
- if (string_node_p(b)) {
- /* a == NODE_DSTR && b == NODE_STR */
- if (string_node_p(c->car)) {
- /* a->[..., NODE_STR] && b == NODE_STR */
- composite_string_node(p, c->car->cdr, b->cdr);
- cons_free(b);
- return a;
- }
-
- push(a, b);
- return a;
- }
- else {
- /* a == NODE_DSTR && b == NODE_DSTR */
- if (string_node_p(c->car) && string_node_p(b->cdr->car)) {
- /* a->[..., NODE_STR] && b->[NODE_STR, ...] */
- node *d = b->cdr;
- cons_free(b);
- composite_string_node(p, c->car->cdr, d->car->cdr);
- cons_free(d->car);
- c->cdr = d->cdr;
- cons_free(d);
- return a;
- }
- else {
- c->cdr = b->cdr;
- cons_free(b);
- return a;
- }
- }
- }
-
- return new_dstr(p, list2(a, b));
+ struct mrb_ast_xstr_node *n = NEW_NODE(xstr, NODE_XSTR);
+ n->list = a;
+ return (node*)n;
}
-/* (:str . (s . len)) */
+/* struct: dsym_node(parts) - uses cons list */
static node*
-new_xstr(parser_state *p, const char *s, int len)
+new_dsym(parser_state *p, node *a)
{
- return cons((node*)NODE_XSTR, cons((node*)strndup(s, len), nint(len)));
+ struct mrb_ast_str_node *n = NEW_NODE(str, NODE_DSYM);
+ n->list = a;
+ return (node*)n;
}
-/* (:xstr . a) */
+/* struct: regx_node(pattern, flags, encoding) */
static node*
-new_dxstr(parser_state *p, node *a)
+new_regx(parser_state *p, node *list, const char *flags, const char *encoding)
{
- return cons((node*)NODE_DXSTR, a);
+ struct mrb_ast_regx_node *n = NEW_NODE(regx, NODE_REGX);
+ n->list = list;
+ n->flags = flags;
+ n->encoding = encoding;
+ return (node*)n;
}
-/* (:dsym . a) */
+/* struct: back_ref_node(n) */
static node*
-new_dsym(parser_state *p, node *a)
+new_back_ref(parser_state *p, int n)
{
- return cons((node*)NODE_DSYM, a);
+ struct mrb_ast_back_ref_node *backref_node = NEW_NODE(back_ref, NODE_BACK_REF);
+ backref_node->type = n;
+ return (node*)backref_node;
}
-/* (:regx . (s . (opt . enc))) */
+/* struct: nth_ref_node(n) */
static node*
-new_regx(parser_state *p, const char *p1, const char* p2, const char* p3)
+new_nth_ref(parser_state *p, int n)
{
- return cons((node*)NODE_REGX, cons((node*)p1, cons((node*)p2, (node*)p3)));
+ struct mrb_ast_nth_ref_node *nthref_node = NEW_NODE(nth_ref, NODE_NTH_REF);
+ nthref_node->nth = n;
+ return (node*)nthref_node;
}
-/* (:dregx . (a . b)) */
+/* struct: heredoc_node(str) */
static node*
-new_dregx(parser_state *p, node *a, node *b)
+new_heredoc(parser_state *p, struct mrb_parser_heredoc_info **infop)
{
- return cons((node*)NODE_DREGX, cons(a, b));
+ struct mrb_ast_heredoc_node *n = NEW_NODE(heredoc, NODE_HEREDOC);
+
+ /* Initialize embedded heredoc info struct */
+ n->info.allow_indent = FALSE;
+ n->info.remove_indent = FALSE;
+ n->info.line_head = FALSE;
+ n->info.indent = 0;
+ n->info.indented = NULL;
+ n->info.type = str_not_parsing; // Will be set by heredoc processing
+ n->info.term = NULL; // Will be set by heredoc processing
+ n->info.term_len = 0;
+ n->info.doc = NULL;
+
+ /* Return pointer to embedded info if requested */
+ *infop = &n->info;
+
+ return (node*)n;
}
-/* (:backref . n) */
-static node*
-new_back_ref(parser_state *p, int n)
+static void
+new_bv(parser_state *p, mrb_sym id)
{
- return cons((node*)NODE_BACK_REF, nint(n));
}
-/* (:nthref . n) */
static node*
-new_nth_ref(parser_state *p, int n)
+new_literal_delim(parser_state *p)
{
- return cons((node*)NODE_NTH_REF, nint(n));
+ return cons((node*)0, (node*)0);
}
-/* (:heredoc . a) */
+/* Helper for creating string representation cons (length . string_ptr) */
static node*
-new_heredoc(parser_state *p)
+new_str_rep(parser_state *p, const char *str, int len)
{
- parser_heredoc_info *inf = (parser_heredoc_info*)parser_palloc(p, sizeof(parser_heredoc_info));
- return cons((node*)NODE_HEREDOC, (node*)inf);
+ return cons(int_to_node(len), (node*)strndup(str, len));
}
-static void
-new_bv(parser_state *p, mrb_sym id)
+/* Helper for creating string representation from current token */
+static node*
+new_str_tok(parser_state *p)
{
+ return new_str_rep(p, tok(p), toklen(p));
}
+/* Helper for creating empty string representation */
static node*
-new_literal_delim(parser_state *p)
+new_str_empty(parser_state *p)
{
- return cons((node*)NODE_LITERAL_DELIM, 0);
+ return new_str_rep(p, "", 0);
}
/* (:words . a) */
static node*
new_words(parser_state *p, node *a)
{
- return cons((node*)NODE_WORDS, a);
+ struct mrb_ast_words_node *words_node = NEW_NODE(words, NODE_WORDS);
+ words_node->args = a;
+ return (node*)words_node;
}
/* (:symbols . a) */
static node*
new_symbols(parser_state *p, node *a)
{
- return cons((node*)NODE_SYMBOLS, a);
+ struct mrb_ast_symbols_node *symbols_node = NEW_NODE(symbols, NODE_SYMBOLS);
+ symbols_node->args = a;
+ return (node*)symbols_node;
}
/* xxx ----------------------------- */
@@ -1252,17 +1700,20 @@ static void
args_with_block(parser_state *p, node *a, node *b)
{
if (b) {
- if (a->cdr && a->cdr->cdr) {
+ /* Handle callargs structure - direct casting like new_args() */
+ struct mrb_ast_callargs *callargs = (struct mrb_ast_callargs*)a;
+ if (callargs->block_arg) {
yyerror(NULL, p, "both block arg and actual block given");
}
- a->cdr->cdr = b;
+ callargs->block_arg = b;
}
}
static void
endless_method_name(parser_state *p, node *defn)
{
- mrb_sym sym = sym(defn->cdr->car);
+ struct mrb_ast_def_node *def = (struct mrb_ast_def_node*)defn;
+ mrb_sym sym = def->name;
mrb_int len;
const char *name = mrb_sym_name_len(p->mrb, sym, &len);
@@ -1277,29 +1728,80 @@ endless_method_name(parser_state *p, node *defn)
static void
call_with_block(parser_state *p, node *a, node *b)
{
- node *n;
+ if (!a) return;
- switch (typen(a->car)) {
+ /* Handle direct variable-sized nodes */
+ struct mrb_ast_var_header *header = (struct mrb_ast_var_header*)a;
+
+ enum node_type var_type = (enum node_type)header->node_type;
+ switch (var_type) {
case NODE_SUPER:
case NODE_ZSUPER:
- if (!a->cdr) a->cdr = new_callargs(p, 0, 0, b);
- else args_with_block(p, a->cdr, b);
+ /* For variable-sized super/zsuper nodes, update the args field directly */
+ {
+ struct mrb_ast_super_node *super_n = super_node(a);
+ if (!super_n->args) {
+ super_n->args = new_callargs(p, 0, 0, b);
+ }
+ else {
+ args_with_block(p, super_n->args, b);
+ }
+ }
break;
- case NODE_CALL:
- case NODE_FCALL:
- case NODE_SCALL:
- /* (NODE_CALL recv mid (args kw . blk)) */
- n = a->cdr->cdr->cdr; /* (args kw . blk) */
- if (!n->car) n->car = new_callargs(p, 0, 0, b);
- else args_with_block(p, n->car, b);
+ case NODE_YIELD:
+ /* Variable-sized yield nodes should generate an error when given a block */
+ yyerror(NULL, p, "block given to yield");
break;
case NODE_RETURN:
+ /* Variable-sized return nodes - recursively call with args */
+ {
+ struct mrb_ast_return_node *return_n = return_node(a);
+ if (return_n->args != NULL) {
+ call_with_block(p, return_n->args, b);
+ }
+ }
+ break;
case NODE_BREAK:
+ /* Variable-sized break nodes - recursively call with value */
+ {
+ struct mrb_ast_break_node *break_n = (struct mrb_ast_break_node*)a;
+ if (break_n->value != NULL) {
+ call_with_block(p, break_n->value, b);
+ }
+ }
+ break;
case NODE_NEXT:
- if (a->cdr == NULL) return;
- call_with_block(p, a->cdr, b);
+ /* Variable-sized next nodes - recursively call with value */
+ {
+ struct mrb_ast_next_node *next_n = (struct mrb_ast_next_node*)a;
+ if (next_n->value != NULL) {
+ call_with_block(p, next_n->value, b);
+ }
+ }
+ break;
+ case NODE_CALL:
+ /* Variable-sized call nodes - add block to existing args */
+ {
+ struct mrb_ast_call_node *call = call_node(a);
+
+ if (call->args && callargs_node(call->args)->block_arg) {
+ yyerror(NULL, p, "both block arg and actual block given");
+ return;
+ }
+
+ /* Use existing args and add block */
+ if (call->args) {
+ /* Modify existing callargs structure to add block */
+ args_with_block(p, call->args, b);
+ }
+ else {
+ /* Create new callargs with just the block */
+ call->args = new_callargs(p, NULL, NULL, b);
+ }
+ }
break;
default:
+ /* For other variable-sized nodes, do nothing */
break;
}
}
@@ -1307,7 +1809,9 @@ call_with_block(parser_state *p, node *a, node *b)
static node*
new_negate(parser_state *p, node *n)
{
- return cons((node*)NODE_NEGATE, n);
+ struct mrb_ast_negate_node *negate_node = NEW_NODE(negate, NODE_NEGATE);
+ negate_node->operand = n;
+ return (node*)negate_node;
}
static node*
@@ -1319,36 +1823,43 @@ cond(node *n)
static node*
ret_args(parser_state *p, node *n)
{
- if (n->cdr->cdr) {
+ /* Handle callargs structure - direct casting like new_args() */
+ struct mrb_ast_callargs *callargs = (struct mrb_ast_callargs*)n;
+ if (callargs->block_arg) {
yyerror(NULL, p, "block argument should not be given");
return NULL;
}
- if (!n->car) return NULL;
- if (!n->car->cdr) return n->car->car;
- return new_array(p, n->car);
+ if (!callargs->regular_args) return NULL;
+ if (!callargs->regular_args->cdr) return callargs->regular_args->car;
+ return new_array(p, callargs->regular_args);
}
static void
assignable(parser_state *p, node *lhs)
{
- switch (intn(lhs->car)) {
+ switch (node_type(lhs)) {
case NODE_LVAR:
- local_add(p, sym(lhs->cdr));
+ local_add(p, var_node(lhs)->symbol);
break;
case NODE_CONST:
if (p->in_def)
yyerror(NULL, p, "dynamic constant assignment");
break;
+ default:
+ /* Other node types don't need special handling in assignable */
+ break;
}
}
static node*
var_reference(parser_state *p, node *lhs)
{
- if (intn(lhs->car) == NODE_LVAR) {
- if (!local_var_p(p, sym(lhs->cdr))) {
- node *n = new_fcall(p, sym(lhs->cdr), 0);
- cons_free(lhs);
+ /* Check if this is a variable-sized node */
+ if (node_type_p(lhs, NODE_LVAR)) {
+ mrb_sym sym = var_node(lhs)->symbol;
+ if (!local_var_p(p, sym)) {
+ node *n = new_fcall(p, sym, 0);
+ /* Don't free variable-sized nodes - they're managed by the parser allocator */
return n;
}
}
@@ -1423,6 +1934,11 @@ parsing_heredoc_info(parser_state *p)
node *nd = p->parsing_heredoc;
if (nd == NULL) return NULL;
/* mrb_assert(nd->car->car == NODE_HEREDOC); */
+ if (node_type(nd->car) == NODE_HEREDOC) {
+ /* Variable-sized heredoc node - return address of embedded info struct */
+ struct mrb_ast_heredoc_node *heredoc = (struct mrb_ast_heredoc_node*)nd->car;
+ return &heredoc->info;
+ }
return (parser_heredoc_info*)nd->car->cdr;
}
@@ -1460,14 +1976,12 @@ prohibit_literals(parser_state *p, node *n)
yyerror(NULL, p, "can't define singleton method for ().");
}
else {
- switch (typen(n->car)) {
+ enum node_type nt = node_type(n);
+ switch (nt) {
case NODE_INT:
case NODE_STR:
- case NODE_DSTR:
case NODE_XSTR:
- case NODE_DXSTR:
- case NODE_DREGX:
- case NODE_MATCH:
+ case NODE_REGX:
case NODE_FLOAT:
case NODE_ARRAY:
case NODE_HEREDOC:
@@ -1540,7 +2054,7 @@ prohibit_literals(parser_state *p, node *n)
modifier_while "'while' modifier"
modifier_until "'until' modifier"
modifier_rescue "'rescue' modifier"
- keyword_alias "'alis'"
+ keyword_alias "'alias'"
keyword_BEGIN "'BEGIN'"
keyword_END "'END'"
keyword__LINE__ "'__LINE__'"
@@ -1586,9 +2100,12 @@ prohibit_literals(parser_state *p, node *n)
%type <nd> heredoc words symbols
%type <num> call_op call_op2 /* 0:'&.', 1:'.', 2:'::' */
-%type <nd> args_tail opt_args_tail f_kwarg f_kw f_kwrest
+%type <nd> args_tail opt_args_tail f_kwarg f_kw
%type <nd> f_block_kwarg f_block_kw block_args_tail opt_block_args_tail
-%type <id> f_label
+%type <id> f_label f_kwrest
+
+/* pattern matching */
+%type <nd> in_clauses p_expr p_alt p_value p_var p_as p_array p_array_body p_array_elems p_rest p_hash p_hash_body p_hash_elems p_hash_elem p_kwrest p_args_head p_args_post p_const
%token tUPLUS "unary plus"
%token tUMINUS "unary minus"
@@ -1635,7 +2152,7 @@ prohibit_literals(parser_state *p, node *n)
%nonassoc tLOWEST
%nonassoc tLBRACE_ARG
-%nonassoc modifier_if modifier_unless modifier_while modifier_until
+%nonassoc modifier_if modifier_unless modifier_while modifier_until keyword_in
%left keyword_or keyword_and
%right keyword_not
%right '=' tOP_ASGN
@@ -1665,7 +2182,6 @@ program : {
top_compstmt
{
p->tree = new_scope(p, $2);
- NODE_LINENO(p->tree, $2);
}
;
@@ -1677,20 +2193,19 @@ top_compstmt : top_stmts opt_terms
top_stmts : none
{
- $$ = new_begin(p, 0);
+ $$ = new_stmts(p, 0);
}
| top_stmt
{
- $$ = new_begin(p, $1);
- NODE_LINENO($$, $1);
+ $$ = new_stmts(p, $1);
}
| top_stmts terms top_stmt
{
- $$ = push($1, newline_node($3));
+ $$ = stmts_push(p, $1, newline_node($3));
}
| error top_stmt
{
- $$ = new_begin(p, 0);
+ $$ = new_stmts(p, 0);
}
;
@@ -1716,11 +2231,10 @@ bodystmt : compstmt
{
if ($2) {
$$ = new_rescue(p, $1, $2, $3);
- NODE_LINENO($$, $1);
}
else if ($3) {
yywarning(p, "else without rescue is useless");
- $$ = push($1, $3);
+ $$ = stmts_push(p, $1, $3);
}
else {
$$ = $1;
@@ -1744,20 +2258,19 @@ compstmt : stmts opt_terms
stmts : none
{
- $$ = new_begin(p, 0);
+ $$ = new_stmts(p, 0);
}
| stmt
{
- $$ = new_begin(p, $1);
- NODE_LINENO($$, $1);
+ $$ = new_stmts(p, $1);
}
| stmts terms stmt
{
- $$ = push($1, newline_node($3));
+ $$ = stmts_push(p, $1, newline_node($3));
}
| error stmt
{
- $$ = new_begin(p, $2);
+ $$ = new_stmts(p, $2);
}
;
@@ -1767,7 +2280,7 @@ stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym
}
| keyword_undef undef_list
{
- $$ = $2;
+ $$ = new_undef(p, $2);
}
| stmt modifier_if expr_value
{
@@ -1775,15 +2288,25 @@ stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym
}
| stmt modifier_unless expr_value
{
- $$ = new_unless(p, cond($3), $1, 0);
+ $$ = new_if(p, cond($3), 0, $1);
}
| stmt modifier_while expr_value
{
- $$ = new_while(p, cond($3), $1);
+ if ($1 && node_type_p($1, NODE_BEGIN)) {
+ $$ = new_while_mod(p, cond($3), $1);
+ }
+ else {
+ $$ = new_while(p, cond($3), $1);
+ }
}
| stmt modifier_until expr_value
{
- $$ = new_until(p, cond($3), $1);
+ if ($1 && node_type_p($1, NODE_BEGIN)) {
+ $$ = new_until_mod(p, cond($3), $1);
+ }
+ else {
+ $$ = new_until(p, cond($3), $1);
+ }
}
| stmt modifier_rescue stmt
{
@@ -1811,12 +2334,6 @@ stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym
{
$$ = new_masgn(p, $1, new_array(p, $3));
}
- | arg tASSOC tIDENTIFIER
- {
- node *lhs = new_lvar(p, $3);
- assignable(p, lhs);
- $$ = new_asgn(p, lhs, $1);
- }
| expr
;
@@ -1871,7 +2388,7 @@ command_asgn : lhs '=' command_rhs
{
$$ = $1;
void_expr_error(p, $4);
- defs_setup(p, $$, $2, $4);
+ defn_setup(p, $$, $2, $4);
nvars_unnest(p);
p->in_def--;
p->in_single--;
@@ -1880,7 +2397,7 @@ command_asgn : lhs '=' command_rhs
{
$$ = $1;
void_expr_error(p, $4);
- defs_setup(p, $$, $2, new_mod_rescue(p, $4, $6));
+ defn_setup(p, $$, $2, new_mod_rescue(p, $4, $6));
nvars_unnest(p);
p->in_def--;
p->in_single--;
@@ -1888,7 +2405,7 @@ command_asgn : lhs '=' command_rhs
| backref tOP_ASGN command_rhs
{
backref_error(p, $1);
- $$ = new_begin(p, 0);
+ $$ = new_stmts(p, 0);
}
;
@@ -1900,7 +2417,6 @@ command_rhs : command_call %prec tOP_ASGN
| command_asgn
;
-
expr : command_call
| expr keyword_and expr
{
@@ -1918,13 +2434,24 @@ expr : command_call
{
$$ = call_uni_op(p, cond($2), "!");
}
- | arg
+ | arg tASSOC {p->in_kwarg++;} p_expr
+ {
+ /* expr => pattern (raises NoMatchingPatternError on failure) */
+ p->in_kwarg--;
+ $$ = new_match_pat(p, $1, $4, TRUE);
+ }
+ | arg keyword_in {p->in_kwarg++;} p_expr
+ {
+ /* expr in pattern (returns true/false) */
+ p->in_kwarg--;
+ $$ = new_match_pat(p, $1, $4, FALSE);
+ }
+ | arg %prec tLOWEST
;
-
defn_head : keyword_def fname
{
- $$ = new_def(p, $2, nint(p->cmdarg_stack), local_switch(p));
+ $$ = new_def(p, $2);
p->cmdarg_stack = 0;
p->in_def++;
nvars_block(p);
@@ -1937,7 +2464,7 @@ defs_head : keyword_def singleton dot_or_colon
}
fname
{
- $$ = new_sdef(p, $2, $5, nint(p->cmdarg_stack), local_switch(p));
+ $$ = new_sdef(p, $2, $5);
p->cmdarg_stack = 0;
p->in_def++;
p->in_single++;
@@ -2207,16 +2734,16 @@ cname : tIDENTIFIER
cpath : tCOLON3 cname
{
- $$ = cons(nint(1), nsym($2));
+ $$ = cons(int_to_node(1), sym_to_node($2));
}
| cname
{
- $$ = cons(nint(0), nsym($1));
+ $$ = cons(int_to_node(0), sym_to_node($1));
}
| primary_value tCOLON2 cname
{
void_expr_error(p, $1);
- $$ = cons($1, nsym($3));
+ $$ = cons($1, sym_to_node($3));
}
;
@@ -2241,11 +2768,11 @@ fsym : fname
undef_list : fsym
{
- $$ = new_undef(p, $1);
+ $$ = cons(sym_to_node($1), 0);
}
| undef_list ',' {p->lstate = EXPR_FNAME;} fsym
{
- $$ = push($1, nsym($4));
+ $$ = push($1, sym_to_node($4));
}
;
@@ -2322,17 +2849,17 @@ arg : lhs '=' arg_rhs
| primary_value tCOLON2 tCONSTANT tOP_ASGN arg_rhs
{
yyerror(&@1, p, "constant re-assignment");
- $$ = new_begin(p, 0);
+ $$ = new_stmts(p, 0);
}
| tCOLON3 tCONSTANT tOP_ASGN arg_rhs
{
yyerror(&@1, p, "constant re-assignment");
- $$ = new_begin(p, 0);
+ $$ = new_stmts(p, 0);
}
| backref tOP_ASGN arg_rhs
{
backref_error(p, $1);
- $$ = new_begin(p, 0);
+ $$ = new_stmts(p, 0);
}
| arg tDOT2 arg
{
@@ -2504,7 +3031,7 @@ arg : lhs '=' arg_rhs
{
$$ = $1;
void_expr_error(p, $4);
- defs_setup(p, $$, $2, $4);
+ defn_setup(p, $$, $2, $4);
nvars_unnest(p);
p->in_def--;
p->in_single--;
@@ -2513,7 +3040,7 @@ arg : lhs '=' arg_rhs
{
$$ = $1;
void_expr_error(p, $4);
- defs_setup(p, $$, $2, new_mod_rescue(p, $4, $6));
+ defn_setup(p, $$, $2, new_mod_rescue(p, $4, $6));
nvars_unnest(p);
p->in_def--;
p->in_single--;
@@ -2528,7 +3055,6 @@ aref_args : none
| args trailer
{
$$ = $1;
- NODE_LINENO($$, $1);
}
| args comma assocs trailer
{
@@ -2536,8 +3062,7 @@ aref_args : none
}
| assocs trailer
{
- $$ = cons(new_kw_hash(p, $1), 0);
- NODE_LINENO($$, $1);
+ $$ = cons(new_hash(p, $1), 0);
}
;
@@ -2562,7 +3087,7 @@ paren_args : '(' opt_call_args ')'
mrb_sym k = intern_op(pow);
mrb_sym b = intern_op(and);
$$ = new_callargs(p, push($2, new_splat(p, new_lvar(p, r))),
- new_kw_hash(p, list1(cons(new_kw_rest_args(p, 0), new_lvar(p, k)))),
+ list1(cons(new_kw_rest_args(p, 0), new_lvar(p, k))),
new_block_arg(p, new_lvar(p, b)));
}
| '(' tBDOT3 rparen
@@ -2572,7 +3097,7 @@ paren_args : '(' opt_call_args ')'
mrb_sym b = intern_op(and);
if (local_var_p(p, r) && local_var_p(p, k) && local_var_p(p, b)) {
$$ = new_callargs(p, list1(new_splat(p, new_lvar(p, r))),
- new_kw_hash(p, list1(cons(new_kw_rest_args(p, 0), new_lvar(p, k)))),
+ list1(cons(new_kw_rest_args(p, 0), new_lvar(p, k))),
new_block_arg(p, new_lvar(p, b)));
}
else {
@@ -2591,17 +3116,14 @@ opt_call_args : none
| args comma
{
$$ = new_callargs(p,$1,0,0);
- NODE_LINENO($$, $1);
}
| args comma assocs comma
{
- $$ = new_callargs(p,$1,new_kw_hash(p,$3),0);
- NODE_LINENO($$, $1);
+ $$ = new_callargs(p,$1,$3,0);
}
| assocs comma
{
- $$ = new_callargs(p,0,new_kw_hash(p,$1),0);
- NODE_LINENO($$, $1);
+ $$ = new_callargs(p,0,$1,0);
}
;
@@ -2609,27 +3131,22 @@ call_args : command
{
void_expr_error(p, $1);
$$ = new_callargs(p, list1($1), 0, 0);
- NODE_LINENO($$, $1);
}
| args opt_block_arg
{
$$ = new_callargs(p, $1, 0, $2);
- NODE_LINENO($$, $1);
}
| assocs opt_block_arg
{
- $$ = new_callargs(p, 0, new_kw_hash(p, $1), $2);
- NODE_LINENO($$, $1);
+ $$ = new_callargs(p, 0, $1, $2);
}
| args comma assocs opt_block_arg
{
- $$ = new_callargs(p, $1, new_kw_hash(p, $3), $4);
- NODE_LINENO($$, $1);
+ $$ = new_callargs(p, $1, $3, $4);
}
| block_arg
{
$$ = new_callargs(p, 0, 0, $1);
- NODE_LINENO($$, $1);
}
;
@@ -2671,7 +3188,6 @@ args : arg
{
void_expr_error(p, $1);
$$ = list1($1);
- NODE_LINENO($$, $1);
}
| tSTAR
{
@@ -2680,7 +3196,6 @@ args : arg
| tSTAR arg
{
$$ = list1(new_splat(p, $2));
- NODE_LINENO($$, $2);
}
| args comma arg
{
@@ -2714,7 +3229,13 @@ mrhs : args comma arg
primary : literal
| string
+ {
+ $$ = new_str(p, $1);
+ }
| xstring
+ {
+ $$ = new_xstr(p, $1);
+ }
| regexp
| heredoc
| var_ref
@@ -2732,14 +3253,14 @@ primary : literal
keyword_end
{
p->cmdarg_stack = $<stack>2;
- $$ = $3;
+ $$ = new_begin(p, $3);
}
| tLPAREN_ARG
{
$<stack>$ = p->cmdarg_stack;
p->cmdarg_stack = 0;
}
- stmt {p->lstate = EXPR_ENDARG;} rparen
+ compstmt {p->lstate = EXPR_ENDARG;} rparen
{
p->cmdarg_stack = $<stack>2;
$$ = $3;
@@ -2763,12 +3284,10 @@ primary : literal
| tLBRACK aref_args ']'
{
$$ = new_array(p, $2);
- NODE_LINENO($$, $2);
}
| tLBRACE assoc_list '}'
{
$$ = new_hash(p, $2);
- NODE_LINENO($$, $2);
}
| keyword_return
{
@@ -2830,7 +3349,7 @@ primary : literal
opt_else
keyword_end
{
- $$ = new_unless(p, cond($2), $4, $5);
+ $$ = new_if(p, cond($2), $5, $4);
SET_LINENO($$, $1);
}
| keyword_while {COND_PUSH(1);} expr_value do {COND_POP();}
@@ -2857,6 +3376,33 @@ primary : literal
{
$$ = new_case(p, 0, $3);
}
+ | keyword_case expr_value opt_terms
+ keyword_in p_expr then
+ compstmt
+ in_clauses
+ keyword_end
+ {
+ node *in_clause = new_in(p, $5, NULL, $7, FALSE);
+ $$ = new_case_match(p, $2, cons(in_clause, $8));
+ }
+ | keyword_case expr_value opt_terms
+ keyword_in p_expr modifier_if expr_value then
+ compstmt
+ in_clauses
+ keyword_end
+ {
+ node *in_clause = new_in(p, $5, $7, $9, FALSE);
+ $$ = new_case_match(p, $2, cons(in_clause, $10));
+ }
+ | keyword_case expr_value opt_terms
+ keyword_in p_expr modifier_unless expr_value then
+ compstmt
+ in_clauses
+ keyword_end
+ {
+ node *in_clause = new_in(p, $5, $7, $9, TRUE);
+ $$ = new_case_match(p, $2, cons(in_clause, $10));
+ }
| keyword_for for_var keyword_in
{COND_PUSH(1);}
expr_value do
@@ -2891,7 +3437,7 @@ primary : literal
}
term
{
- $<nd>$ = cons(local_switch(p), nint(p->in_single));
+ $<nd>$ = cons(local_switch(p), int_to_node(p->in_single));
nvars_block(p);
p->in_single = 0;
}
@@ -2903,7 +3449,7 @@ primary : literal
local_resume(p, $<nd>6->car);
nvars_unnest(p);
p->in_def = $<num>4;
- p->in_single = intn($<nd>6->cdr);
+ p->in_single = node_to_int($<nd>6->cdr);
}
| keyword_module
cpath
@@ -2937,7 +3483,7 @@ primary : literal
keyword_end
{
$$ = $1;
- defs_setup(p, $$, $2, $3);
+ defn_setup(p, $$, $2, $3);
nvars_unnest(p);
p->in_def--;
p->in_single--;
@@ -3005,33 +3551,33 @@ f_margs : f_arg
}
| f_arg ',' tSTAR f_norm_arg
{
- $$ = list3($1, new_arg(p, $4), 0);
+ $$ = list3($1, new_lvar(p, $4), 0);
}
| f_arg ',' tSTAR f_norm_arg ',' f_arg
{
- $$ = list3($1, new_arg(p, $4), $6);
+ $$ = list3($1, new_lvar(p, $4), $6);
}
| f_arg ',' tSTAR
{
local_add_f(p, intern_op(mul));
- $$ = list3($1, nint(-1), 0);
+ $$ = list3($1, int_to_node(-1), 0);
}
| f_arg ',' tSTAR ',' f_arg
{
- $$ = list3($1, nint(-1), $5);
+ $$ = list3($1, int_to_node(-1), $5);
}
| tSTAR f_norm_arg
{
- $$ = list3(0, new_arg(p, $2), 0);
+ $$ = list3(0, new_lvar(p, $2), 0);
}
| tSTAR f_norm_arg ',' f_arg
{
- $$ = list3(0, new_arg(p, $2), $4);
+ $$ = list3(0, new_lvar(p, $2), $4);
}
| tSTAR
{
local_add_f(p, intern_op(mul));
- $$ = list3(0, nint(-1), 0);
+ $$ = list3(0, int_to_node(-1), 0);
}
| tSTAR ','
{
@@ -3039,7 +3585,7 @@ f_margs : f_arg
}
f_arg
{
- $$ = list3(0, nint(-1), $4);
+ $$ = list3(0, int_to_node(-1), $4);
}
;
@@ -3160,7 +3706,6 @@ block_param_def : '|' {local_add_blk(p);} opt_bv_decl '|'
}
;
-
opt_bv_decl : opt_nl
{
$$ = 0;
@@ -3222,12 +3767,7 @@ do_block : keyword_do_block
block_call : command do_block
{
- if (typen($1->car) == NODE_YIELD) {
- yyerror(&@1, p, "block given to yield");
- }
- else {
- call_with_block(p, $1, $2);
- }
+ call_with_block(p, $1, $2);
$$ = $1;
}
| block_call call_op2 operation2 opt_paren_args
@@ -3264,11 +3804,11 @@ method_call : operation paren_args
}
| primary_value call_op paren_args
{
- $$ = new_call(p, $1, MRB_SYM_2(p->mrb, call), $3, $2);
+ $$ = new_call(p, $1, MRB_SYM(call), $3, $2);
}
| primary_value tCOLON2 paren_args
{
- $$ = new_call(p, $1, MRB_SYM_2(p->mrb, call), $3, tCOLON2);
+ $$ = new_call(p, $1, MRB_SYM(call), $3, tCOLON2);
}
| keyword_super paren_args
{
@@ -3334,6 +3874,300 @@ cases : opt_else
| case_body
;
+/* Pattern matching in-clauses for case/in */
+/* in_kwarg is set by lexer when keyword_in is returned */
+in_clauses : opt_else
+ {
+ $$ = $1 ? list1(new_in(p, NULL, NULL, $1, FALSE)) : 0;
+ }
+ | keyword_in p_expr {p->in_kwarg--;} then compstmt in_clauses
+ {
+ node *in_clause = new_in(p, $2, NULL, $5, FALSE);
+ $$ = cons(in_clause, $6);
+ }
+ | keyword_in p_expr {p->in_kwarg--;} modifier_if expr_value then compstmt in_clauses
+ {
+ node *in_clause = new_in(p, $2, $5, $7, FALSE);
+ $$ = cons(in_clause, $8);
+ }
+ | keyword_in p_expr {p->in_kwarg--;} modifier_unless expr_value then compstmt in_clauses
+ {
+ node *in_clause = new_in(p, $2, $5, $7, TRUE);
+ $$ = cons(in_clause, $8);
+ }
+ ;
+
+/* Pattern expressions for case/in */
+/* Bracket-less array patterns: in 1, 2, x is same as in [1, 2, x] */
+/* Brace-less hash patterns: in a:, b: x is same as in {a:, b: x} */
+p_expr : p_as
+ | p_args_head p_as
+ {
+ $$ = new_pat_array(p, push($1, $2), 0, 0);
+ }
+ | p_args_head p_rest
+ {
+ $$ = new_pat_array(p, $1, $2, 0);
+ }
+ | p_args_head p_rest ',' p_args_post
+ {
+ $$ = new_pat_array(p, $1, $2, $4);
+ }
+ | p_rest
+ {
+ $$ = new_pat_array(p, 0, $1, 0);
+ }
+ | p_rest ',' p_args_post
+ {
+ $$ = new_pat_array(p, 0, $1, $3);
+ }
+ | p_hash_elems
+ {
+ /* Brace-less hash pattern: in a:, b: x */
+ $$ = new_pat_hash(p, $1, 0);
+ }
+ | p_hash_elems ',' p_kwrest
+ {
+ /* Brace-less hash pattern with kwrest: in a:, **rest */
+ $$ = new_pat_hash(p, $1, $3);
+ }
+ | p_kwrest
+ {
+ /* Brace-less kwrest only: in **rest */
+ $$ = new_pat_hash(p, 0, $1);
+ }
+ ;
+
+/* Comma-separated pattern list (prefix) */
+p_args_head : p_as ','
+ {
+ $$ = list1($1);
+ }
+ | p_args_head p_as ','
+ {
+ $$ = push($1, $2);
+ }
+ ;
+
+/* Comma-separated pattern list (suffix, no trailing comma) */
+p_args_post : p_as
+ {
+ $$ = list1($1);
+ }
+ | p_args_post ',' p_as
+ {
+ $$ = push($1, $3);
+ }
+ ;
+
+p_as : p_alt
+ | p_alt tASSOC tIDENTIFIER
+ {
+ $$ = new_pat_as(p, $1, $3);
+ }
+ ;
+
+p_alt : p_value
+ | p_alt '|' p_value
+ {
+ $$ = new_pat_alt(p, $1, $3);
+ }
+ ;
+
+p_value : p_var
+ | numeric
+ {
+ $$ = new_pat_value(p, $1);
+ }
+ | symbol
+ {
+ $$ = new_pat_value(p, $1);
+ }
+ | tSTRING
+ {
+ $$ = new_pat_value(p, new_str(p, list1($1)));
+ }
+ | keyword_nil
+ {
+ $$ = new_pat_value(p, new_nil(p));
+ }
+ | keyword_true
+ {
+ $$ = new_pat_value(p, new_true(p));
+ }
+ | keyword_false
+ {
+ $$ = new_pat_value(p, new_false(p));
+ }
+ | p_const
+ {
+ $$ = new_pat_value(p, $1);
+ }
+ | p_array
+ | p_hash
+ | '^' tIDENTIFIER
+ {
+ $$ = new_pat_pin(p, $2);
+ }
+ ;
+
+/* Array pattern: [a, b, *rest, c] */
+p_array : tLBRACK p_array_body ']'
+ {
+ $$ = $2;
+ }
+ | tLBRACK ']'
+ {
+ $$ = new_pat_array(p, 0, 0, 0);
+ }
+ ;
+
+/* Array pattern body - pre elements, optional rest, post elements */
+p_array_body : p_array_elems
+ {
+ /* Just pre elements, no rest */
+ $$ = new_pat_array(p, $1, 0, 0);
+ }
+ | p_array_elems ',' p_rest
+ {
+ /* Pre elements + rest, no post */
+ $$ = new_pat_array(p, $1, $3, 0);
+ }
+ | p_array_elems ',' p_rest ',' p_array_elems
+ {
+ /* Pre + rest + post */
+ $$ = new_pat_array(p, $1, $3, $5);
+ }
+ | p_rest
+ {
+ /* Just rest, no pre or post */
+ $$ = new_pat_array(p, 0, $1, 0);
+ }
+ | p_rest ',' p_array_elems
+ {
+ /* Rest + post, no pre */
+ $$ = new_pat_array(p, 0, $1, $3);
+ }
+ | p_rest ',' p_array_elems ',' p_rest
+ {
+ /* Find pattern: [*pre, elems, *post] */
+ $$ = new_pat_find(p, $1, $3, $5);
+ }
+ ;
+
+/* Non-rest array pattern elements - use p_as, not p_expr to avoid bracket-less recursion */
+p_array_elems : p_as
+ {
+ $$ = list1($1);
+ }
+ | p_array_elems ',' p_as
+ {
+ $$ = push($1, $3);
+ }
+ ;
+
+/* Rest pattern in array: *var, *_, or just * */
+p_rest : tSTAR tIDENTIFIER
+ {
+ $$ = new_pat_var(p, $2);
+ }
+ | tSTAR
+ {
+ /* Anonymous rest pattern */
+ $$ = (node*)-1;
+ }
+ ;
+
+/* Constant path for pattern matching: Foo, Foo::Bar, ::Foo */
+p_const : tCONSTANT
+ {
+ $$ = new_const(p, $1);
+ }
+ | p_const tCOLON2 tCONSTANT
+ {
+ $$ = new_colon2(p, $1, $3);
+ }
+ | tCOLON3 tCONSTANT
+ {
+ $$ = new_colon3(p, $2);
+ }
+ ;
+
+/* Hash pattern: {a:, b: x, **rest} */
+p_hash : tLBRACE p_hash_body '}'
+ {
+ $$ = $2;
+ }
+ | tLBRACE '}'
+ {
+ $$ = new_pat_hash(p, 0, 0);
+ }
+ ;
+
+/* Hash pattern body - pairs and optional kwrest */
+p_hash_body : p_hash_elems
+ {
+ $$ = new_pat_hash(p, $1, 0);
+ }
+ | p_hash_elems ',' p_kwrest
+ {
+ $$ = new_pat_hash(p, $1, $3);
+ }
+ | p_kwrest
+ {
+ $$ = new_pat_hash(p, 0, $1);
+ }
+ ;
+
+/* Hash pattern element list */
+p_hash_elems : p_hash_elem
+ {
+ $$ = list1($1);
+ }
+ | p_hash_elems ',' p_hash_elem
+ {
+ $$ = push($1, $3);
+ }
+ ;
+
+/* Hash pattern element: key: pattern or key: (shorthand) */
+/* Use p_as, not p_expr to avoid brace-less recursion inside hash patterns */
+/* Note: CRuby only supports label syntax (foo:), not hashrocket (:foo =>) */
+p_hash_elem : tIDENTIFIER tLABEL_TAG p_as
+ {
+ /* {key: pattern} */
+ $$ = cons(new_sym(p, $1), $3);
+ }
+ | tIDENTIFIER tLABEL_TAG
+ {
+ /* {key:} shorthand - binds to variable with same name */
+ $$ = cons(new_sym(p, $1), new_pat_var(p, $1));
+ }
+ ;
+
+/* Keyword rest pattern: **var, **nil, or ** */
+p_kwrest : tDSTAR tIDENTIFIER
+ {
+ $$ = new_pat_var(p, $2);
+ }
+ | tDSTAR keyword_nil
+ {
+ /* **nil - exact match, no extra keys allowed */
+ $$ = (node*)-1;
+ }
+ | tDSTAR
+ {
+ /* ** - anonymous rest, discards extra keys */
+ $$ = (node*)-2;
+ }
+ ;
+
+p_var : tIDENTIFIER
+ {
+ $$ = new_pat_var(p, $1);
+ }
+ ;
+
opt_rescue : keyword_rescue exc_list exc_var then
compstmt
opt_rescue
@@ -3375,26 +4209,28 @@ literal : numeric
string : string_fragment
| string string_fragment
{
- $$ = concat_string(p, $1, $2);
+ $$ = append($1, $2);
}
;
string_fragment : tCHAR
+ {
+ /* tCHAR is (len . str), wrap as cons list */
+ $$ = list1($1);
+ }
| tSTRING
+ {
+ /* tSTRING is (len . str), wrap as cons list */
+ $$ = list1($1);
+ }
| tSTRING_BEG tSTRING
{
- $$ = $2;
+ /* $2 is (len . str), wrap as cons list */
+ $$ = list1($2);
}
| tSTRING_BEG string_rep tSTRING
{
- node *n = $2;
- if (intn($3->cdr->cdr) > 0) {
- n = push(n, $3);
- }
- else {
- cons_free($3);
- }
- $$ = new_dstr(p, n);
+ $$ = push($2, $3);
}
;
@@ -3407,6 +4243,7 @@ string_rep : string_interp
string_interp : tSTRING_MID
{
+ /* $1 is already in (len . str) format */
$$ = list1($1);
}
| tSTRING_PART
@@ -3417,7 +4254,9 @@ string_interp : tSTRING_MID
'}'
{
pop_strterm(p,$<nd>2);
- $$ = list2($1, $3);
+ /* $1 is already in (len . str) format, create (-1 . node) for expression */
+ node *expr_elem = cons(int_to_node(-1), $3);
+ $$ = list2($1, expr_elem);
}
| tLITERAL_DELIM
{
@@ -3431,28 +4270,31 @@ string_interp : tSTRING_MID
xstring : tXSTRING_BEG tXSTRING
{
- $$ = $2;
+ $$ = cons($2, (node*)NULL);
}
| tXSTRING_BEG string_rep tXSTRING
{
- node *n = $2;
- if (intn($3->cdr->cdr) > 0) {
- n = push(n, $3);
- }
- else {
- cons_free($3);
- }
- $$ = new_dxstr(p, n);
+ $$ = push($2, $3);
}
;
regexp : tREGEXP_BEG tREGEXP
{
- $$ = $2;
+ node *data = $2; /* ((len . pattern) . (flags . encoding)) */
+ const char *flags = (const char*)data->cdr->car;
+ const char *encoding = (const char*)data->cdr->cdr;
+ /* Use data->car directly as pattern_list: (len . pattern) */
+ node *pattern_list = cons(data->car, (node*)NULL);
+ $$ = new_regx(p, pattern_list, flags, encoding);
}
| tREGEXP_BEG string_rep tREGEXP
{
- $$ = new_dregx(p, $2, $3);
+ node *data = $3; /* ((len . pattern) . (flags . encoding)) */
+ const char *flags = (const char*)data->cdr->car;
+ const char *encoding = (const char*)data->cdr->cdr;
+ /* Append the pattern from $3->car to the string list $2 */
+ node *complete_list = push($2, data->car);
+ $$ = new_regx(p, complete_list, flags, encoding);
}
;
@@ -3466,7 +4308,7 @@ heredoc_bodies : heredoc_body
heredoc_body : tHEREDOC_END
{
parser_heredoc_info *info = parsing_heredoc_info(p);
- info->doc = push(info->doc, new_str(p, "", 0));
+ info->doc = push(info->doc, new_str_empty(p));
heredoc_end(p);
}
| heredoc_string_rep tHEREDOC_END
@@ -3494,7 +4336,9 @@ heredoc_string_interp : tHD_STRING_MID
{
pop_strterm(p, $<nd>2);
parser_heredoc_info *info = parsing_heredoc_info(p);
- info->doc = push(push(info->doc, $1), $3);
+ /* $1 is already in (len . str) format, create (-1 . node) for expression */
+ node *expr_elem = cons(int_to_node(-1), $3);
+ info->doc = push(push(info->doc, $1), expr_elem);
}
;
@@ -3505,17 +4349,11 @@ words : tWORDS_BEG tSTRING
| tWORDS_BEG string_rep tSTRING
{
node *n = $2;
- if (intn($3->cdr->cdr) > 0) {
- n = push(n, $3);
- }
- else {
- cons_free($3);
- }
+ n = push(n, $3);
$$ = new_words(p, n);
}
;
-
symbol : basic_symbol
{
$$ = new_sym(p, $1);
@@ -3524,13 +4362,13 @@ symbol : basic_symbol
{
node *n = $3;
p->lstate = EXPR_ENDARG;
- if (intn($4->cdr->cdr) > 0) {
+ if (node_to_int($4->car) > 0) {
n = push(n, $4);
}
else {
cons_free($4);
}
- $$ = new_dsym(p, new_dstr(p, n));
+ $$ = new_dsym(p, n);
}
| tSYMBEG tNUMPARAM
{
@@ -3567,9 +4405,7 @@ symbols : tSYMBOLS_BEG tSTRING
| tSYMBOLS_BEG string_rep tSTRING
{
node *n = $2;
- if (intn($3->cdr->cdr) > 0) {
- n = push(n, $3);
- }
+ n = push(n, $3);
$$ = new_symbols(p, n);
}
;
@@ -3648,7 +4484,7 @@ var_ref : variable
if (!fn) {
fn = "(null)";
}
- $$ = new_str(p, fn, strlen(fn));
+ $$ = new_str(p, cons(cons(int_to_node(strlen(fn)), (node*)fn), (node*)NULL));
}
| keyword__LINE__
{
@@ -3659,7 +4495,7 @@ var_ref : variable
}
| keyword__ENCODING__
{
- $$ = new_fcall(p, MRB_SYM_2(p->mrb, __ENCODING__), 0);
+ $$ = new_fcall(p, MRB_SYM(__ENCODING__), 0);
}
;
@@ -3725,11 +4561,15 @@ f_arglist : f_arglist_paren
f_label : tIDENTIFIER tLABEL_TAG
{
+ $$ = $1;
local_nest(p);
+ p->lstate = EXPR_MID; /* make newlines significant after label */
}
| tNUMPARAM tLABEL_TAG
{
+ $$ = intern_numparam($1);
local_nest(p);
+ p->lstate = EXPR_MID; /* make newlines significant after label */
}
;
@@ -3785,11 +4625,11 @@ kwrest_mark : tPOW
f_kwrest : kwrest_mark tIDENTIFIER
{
- $$ = new_kw_rest_args(p, $2);
+ $$ = $2;
}
| kwrest_mark
{
- $$ = new_kw_rest_args(p, 0);
+ $$ = intern_op(pow);
}
;
@@ -3815,6 +4655,10 @@ opt_args_tail : ',' args_tail
{
$$ = $2;
}
+ | ','
+ {
+ $$ = new_args_tail(p, 0, 0, 0);
+ }
| /* none */
{
$$ = new_args_tail(p, 0, 0, 0);
@@ -3924,7 +4768,7 @@ f_norm_arg : f_bad_arg
f_arg_item : f_norm_arg
{
- $$ = new_arg(p, $1);
+ $$ = new_lvar(p, $1);
}
| tLPAREN
{
@@ -3932,7 +4776,7 @@ f_arg_item : f_norm_arg
}
f_margs rparen
{
- $$ = new_masgn_param(p, $3, p->locals->car);
+ $$ = new_marg(p, $3);
local_resume(p, $<nd>2);
local_add_f(p, 0);
}
@@ -3959,7 +4803,7 @@ f_opt_asgn : tIDENTIFIER '='
f_opt : f_opt_asgn arg
{
void_expr_error(p, $2);
- $$ = cons(nsym($1), cons($2, locals_node(p)));
+ $$ = cons(sym_to_node($1), cons($2, locals_node(p)));
local_unnest(p);
}
;
@@ -3967,7 +4811,7 @@ f_opt : f_opt_asgn arg
f_block_opt : f_opt_asgn primary_value
{
void_expr_error(p, $2);
- $$ = cons(nsym($1), cons($2, locals_node(p)));
+ $$ = cons(sym_to_node($1), cons($2, locals_node(p)));
local_unnest(p);
}
;
@@ -4016,6 +4860,10 @@ f_block_arg : blkarg_mark tIDENTIFIER
{
$$ = $2;
}
+ | blkarg_mark keyword_nil
+ {
+ $$ = MRB_SYM(nil);
+ }
| blkarg_mark
{
$$ = intern_op(and);
@@ -4026,6 +4874,10 @@ opt_f_block_arg : ',' f_block_arg
{
$$ = $2;
}
+ | ','
+ {
+ $$ = 0;
+ }
| none
{
$$ = 0;
@@ -4055,7 +4907,6 @@ assoc_list : none
assocs : assoc
{
$$ = list1($1);
- NODE_LINENO($$, $1);
}
| assocs comma assoc
{
@@ -4091,11 +4942,17 @@ assoc : arg tASSOC arg
| string_fragment tLABEL_TAG arg
{
void_expr_error(p, $3);
- if (typen($1->car) == NODE_DSTR) {
+ if ($1->cdr) {
+ /* Multiple fragments - create dynamic symbol */
+ $$ = cons(new_dsym(p, $1), $3);
+ }
+ else if (node_to_int($1->car->car) < 0) {
+ /* Single fragment but it's an expression (-1 . node) - create dynamic symbol */
$$ = cons(new_dsym(p, $1), $3);
}
else {
- $$ = cons(new_sym(p, new_strsym(p, $1)), $3);
+ /* Single string fragment - create simple symbol */
+ $$ = cons(new_sym(p, new_strsym(p, $1->car)), $3);
}
}
| tDSTAR arg
@@ -4270,13 +5127,13 @@ backref_error(parser_state *p, node *n)
{
int c;
- c = intn(n->car);
+ c = node_to_int(n->car);
if (c == NODE_NTH_REF) {
- yyerror_c(p, "can't set variable $", (char)intn(n->cdr)+'0');
+ yyerror_c(p, "can't set variable $", (char)node_to_int(n->cdr)+'0');
}
else if (c == NODE_BACK_REF) {
- yyerror_c(p, "can't set variable $", (char)intn(n->cdr));
+ yyerror_c(p, "can't set variable $", (char)node_to_int(n->cdr));
}
else {
yyerror(NULL, p, "Internal error in backref_error()");
@@ -4286,36 +5143,56 @@ backref_error(parser_state *p, node *n)
static void
void_expr_error(parser_state *p, node *n)
{
- int c;
-
if (n == NULL) return;
- c = intn(n->car);
- switch (c) {
- case NODE_BREAK:
- case NODE_RETURN:
- case NODE_NEXT:
- case NODE_REDO:
- case NODE_RETRY:
- yyerror(NULL, p, "void value expression");
- break;
- case NODE_AND:
- case NODE_OR:
- if (n->cdr) {
- void_expr_error(p, n->cdr->car);
- void_expr_error(p, n->cdr->cdr);
- }
- break;
- case NODE_BEGIN:
- if (n->cdr) {
- while (n->cdr) {
- n = n->cdr;
+
+ /* Check if this is a variable-sized node first */
+ struct mrb_ast_var_header *header = (struct mrb_ast_var_header*)n;
+ if (header) {
+ /* Handle variable-sized nodes */
+ switch ((enum node_type)header->node_type) {
+ case NODE_BREAK:
+ case NODE_RETURN:
+ case NODE_NEXT:
+ case NODE_REDO:
+ case NODE_RETRY:
+ yyerror(NULL, p, "void value expression");
+ return;
+ case NODE_AND:
+ case NODE_OR:
+ {
+ struct mrb_ast_and_node *and_n = (struct mrb_ast_and_node*)n;
+ void_expr_error(p, (node*)and_n->left);
+ void_expr_error(p, (node*)and_n->right);
}
- void_expr_error(p, n->car);
+ return;
+ case NODE_STMTS:
+ {
+ struct mrb_ast_stmts_node *stmts = (struct mrb_ast_stmts_node*)n;
+ node *last = stmts->stmts;
+ if (last) {
+ /* Find the last statement in the cons list */
+ while (last->cdr) {
+ last = last->cdr;
+ }
+ void_expr_error(p, last->car);
+ }
+ }
+ return;
+ case NODE_BEGIN:
+ {
+ struct mrb_ast_begin_node *begin_n = (struct mrb_ast_begin_node*)n;
+ if (begin_n->body) {
+ void_expr_error(p, (node*)begin_n->body);
+ }
+ }
+ return;
+ default:
+ /* Other variable-sized nodes are OK */
+ return;
}
- break;
- default:
- break;
}
+
+ /* Should not reach here - all nodes should be variable-sized now */
}
static void pushback(parser_state *p, int c);
@@ -4349,7 +5226,7 @@ nextc(parser_state *p)
if (p->pb) {
node *tmp;
- c = intn(p->pb->car);
+ c = node_to_int(p->pb->car);
tmp = p->pb;
p->pb = p->pb->cdr;
cons_free(tmp);
@@ -4385,7 +5262,7 @@ pushback(parser_state *p, int c)
if (c >= 0) {
p->column--;
}
- p->pb = cons(nint(c), p->pb);
+ p->pb = cons(int_to_node(c), p->pb);
}
static void
@@ -4410,7 +5287,7 @@ peekc_n(parser_state *p, int n)
c0 = nextc(p);
if (c0 == -1) return c0; /* do not skip partial EOF */
if (c0 >= 0) --p->column;
- list = push(list, nint(c0));
+ list = push(list, int_to_node(c0));
} while(n--);
if (p->pb) {
p->pb = append(list, p->pb);
@@ -4477,19 +5354,18 @@ skips(parser_state *p, const char *s)
}
return TRUE;
}
- else{
+ else {
s--;
}
}
return FALSE;
}
-
static int
newtok(parser_state *p)
{
if (p->tokbuf != p->buf) {
- mrb_free(p->mrb, p->tokbuf);
+ mrbc_free(p->tokbuf);
p->tokbuf = p->buf;
p->tsiz = MRB_PARSER_TOKBUF_SIZE;
}
@@ -4510,30 +5386,8 @@ tokadd(parser_state *p, int32_t c)
len = 1;
}
else {
- /* Unicode character */
- c = -c;
- if (c < 0x80) {
- utf8[0] = (char)c;
- len = 1;
- }
- else if (c < 0x800) {
- utf8[0] = (char)(0xC0 | (c >> 6));
- utf8[1] = (char)(0x80 | (c & 0x3F));
- len = 2;
- }
- else if (c < 0x10000) {
- utf8[0] = (char)(0xE0 | (c >> 12) );
- utf8[1] = (char)(0x80 | ((c >> 6) & 0x3F));
- utf8[2] = (char)(0x80 | ( c & 0x3F));
- len = 3;
- }
- else {
- utf8[0] = (char)(0xF0 | (c >> 18) );
- utf8[1] = (char)(0x80 | ((c >> 12) & 0x3F));
- utf8[2] = (char)(0x80 | ((c >> 6) & 0x3F));
- utf8[3] = (char)(0x80 | ( c & 0x3F));
- len = 4;
- }
+ /* Unicode character (negative c indicates codepoint) */
+ len = (int)mrb_utf8_to_buf(utf8, (uint32_t)(-c));
}
if (p->tidx+len >= p->tsiz) {
if (p->tsiz >= MRB_PARSER_TOKBUF_MAX) {
@@ -4542,11 +5396,11 @@ tokadd(parser_state *p, int32_t c)
}
p->tsiz *= 2;
if (p->tokbuf == p->buf) {
- p->tokbuf = (char*)mrb_malloc(p->mrb, p->tsiz);
+ p->tokbuf = (char*)mrbc_malloc(p->tsiz);
memcpy(p->tokbuf, p->buf, MRB_PARSER_TOKBUF_SIZE);
}
else {
- p->tokbuf = (char*)mrb_realloc(p->mrb, p->tokbuf, p->tsiz);
+ p->tokbuf = (char*)mrbc_realloc(p->tokbuf, p->tsiz);
}
}
for (i = 0; i < len; i++) {
@@ -4586,7 +5440,7 @@ toklen(parser_state *p)
#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_POSSIBLE() ((p->lstate == EXPR_BEG && !cmd_state) || IS_ARG() || p->lstate == EXPR_VALUE)
#define IS_LABEL_SUFFIX(n) (peek_n(p, ':',(n)) && !peek_n(p, ':', (n)+1))
static int32_t
@@ -4826,8 +5680,8 @@ heredoc_remove_indent(parser_state *p, parser_heredoc_info *hinfo)
while (indented) {
n = indented->car;
pair = n->car;
- str = (char*)pair->car;
- len = (size_t)pair->cdr;
+ len = (size_t)pair->car;
+ str = (char*)pair->cdr;
escaped = n->cdr->car;
nspaces = n->cdr->cdr;
if (escaped) {
@@ -4850,14 +5704,14 @@ heredoc_remove_indent(parser_state *p, parser_heredoc_info *hinfo)
}
if (newlen < len)
newstr[newlen] = '\0';
- pair->car = (node*)newstr;
- pair->cdr = (node*)newlen;
+ pair->car = (node*)newlen;
+ pair->cdr = (node*)newstr;
}
else {
spaces = (size_t)nspaces->car;
heredoc_count_indent(hinfo, str, len, spaces, &offset);
- pair->car = (node*)(str + offset);
- pair->cdr = (node*)(len - offset);
+ pair->car = (node*)(len - offset);
+ pair->cdr = (node*)(str + offset);
}
indented = indented->cdr;
}
@@ -4937,11 +5791,10 @@ parse_string(parser_state *p)
}
return 0;
}
- node *nd = new_str(p, tok(p), toklen(p));
- pylval.nd = nd;
+ pylval.nd = new_str_tok(p);
if (unindent && head) {
- nspaces = push(nspaces, nint(spaces));
- heredoc_push_indented(p, hinfo, nd->cdr, escaped, nspaces, empty && line_head);
+ nspaces = push(nspaces, int_to_node(spaces));
+ heredoc_push_indented(p, hinfo, pylval.nd, escaped, nspaces, empty && line_head);
}
return tHD_STRING_MID;
}
@@ -4975,8 +5828,8 @@ parse_string(parser_state *p)
p->lineno++;
p->column = 0;
if (unindent) {
- nspaces = push(nspaces, nint(spaces));
- escaped = push(escaped, nint(pos));
+ nspaces = push(nspaces, int_to_node(spaces));
+ escaped = push(escaped, int_to_node(pos));
pos--;
empty = TRUE;
spaces = 0;
@@ -5030,12 +5883,11 @@ parse_string(parser_state *p)
tokfix(p);
p->lstate = EXPR_BEG;
p->cmd_start = TRUE;
- node *nd = new_str(p, tok(p), toklen(p));
- pylval.nd = nd;
+ pylval.nd = new_str_tok(p);
if (hinfo) {
if (unindent && head) {
- nspaces = push(nspaces, nint(spaces));
- heredoc_push_indented(p, hinfo, nd->cdr, escaped, nspaces, FALSE);
+ nspaces = push(nspaces, int_to_node(spaces));
+ heredoc_push_indented(p, hinfo, pylval.nd, escaped, nspaces, FALSE);
}
hinfo->line_head = FALSE;
return tHD_STRING_PART;
@@ -5065,7 +5917,7 @@ parse_string(parser_state *p)
else {
pushback(p, c);
tokfix(p);
- pylval.nd = new_str(p, tok(p), toklen(p));
+ pylval.nd = new_str_tok(p);
return tSTRING_MID;
}
}
@@ -5081,14 +5933,15 @@ parse_string(parser_state *p)
end_strterm(p);
if (type & STR_FUNC_XQUOTE) {
- pylval.nd = new_xstr(p, tok(p), toklen(p));
+ pylval.nd = new_str_tok(p);
return tXSTRING;
}
if (type & STR_FUNC_REGEXP) {
int f = 0;
int re_opt;
- char *s = strndup(tok(p), toklen(p));
+ int pattern_len = toklen(p);
+ char *s = strndup(tok(p), pattern_len);
char flags[3];
char *flag = flags;
char enc = '\0';
@@ -5139,11 +5992,11 @@ parse_string(parser_state *p)
else {
encp = NULL;
}
- pylval.nd = new_regx(p, s, dup, encp);
+ pylval.nd = cons(cons(int_to_node(pattern_len), (node*)s), cons((node*)dup, (node*)encp));
return tREGEXP;
}
- pylval.nd = new_str(p, tok(p), toklen(p));
+ pylval.nd = new_str_tok(p);
return tSTRING;
}
@@ -5157,7 +6010,7 @@ number_literal_suffix(parser_state *p)
int mask = NUM_SUFFIX_R|NUM_SUFFIX_I;
while ((c = nextc(p)) != -1) {
- list = push(list, nint(c));
+ list = push(list, int_to_node(c));
if ((mask & NUM_SUFFIX_I) && c == 'i') {
result |= (mask & NUM_SUFFIX_I);
@@ -5244,8 +6097,7 @@ heredoc_identifier(parser_state *p)
pushback(p, c);
}
tokfix(p);
- newnode = new_heredoc(p);
- info = (parser_heredoc_info*)newnode->cdr;
+ newnode = new_heredoc(p, &info);
info->term = strndup(tok(p), toklen(p));
info->term_len = toklen(p);
if (! quote)
@@ -5283,6 +6135,11 @@ parser_yylex(parser_state *p)
enum mrb_lex_state_enum last_state;
int token_column;
+ /* Early termination if too many errors - prevents DoS from malformed input */
+ if (p->nerr > 10) {
+ return 0; /* EOF */
+ }
+
if (p->lex_strterm) {
if (is_strterm_type(p, STR_FUNC_HEREDOC)) {
if (p->parsing_heredoc != NULL)
@@ -5637,7 +6494,7 @@ parser_yylex(parser_state *p)
tokadd(p, c);
}
tokfix(p);
- pylval.nd = new_str(p, tok(p), toklen(p));
+ pylval.nd = new_str_tok(p);
p->lstate = EXPR_END;
return tCHAR;
@@ -6050,7 +6907,8 @@ parser_yylex(parser_state *p)
}
if (!space_seen && IS_END()) {
pushback(p, c);
- p->lstate = EXPR_BEG;
+ /* In pattern matching context, use EXPR_ARG so newlines are significant */
+ p->lstate = p->in_kwarg ? EXPR_ARG : EXPR_BEG;
return tLABEL_TAG;
}
if (IS_END() || ISSPACE(c) || c == '#') {
@@ -6473,7 +7331,7 @@ parser_yylex(parser_state *p)
int nvar;
if (n > 0) {
- nvar = intn(p->nvars->car);
+ nvar = node_to_int(p->nvars->car);
if (nvar != -2) { /* numbered parameters never appear on toplevel */
pylval.num = n;
p->lstate = EXPR_END;
@@ -6552,6 +7410,10 @@ parser_yylex(parser_state *p)
return keyword_do_block;
return keyword_do;
}
+ if (kw->id[0] == keyword_in) {
+ /* Set in_kwarg for pattern matching context */
+ p->in_kwarg++;
+ }
if (state == EXPR_BEG || state == EXPR_VALUE || state == EXPR_CLASS)
return kw->id[0];
else {
@@ -6613,6 +7475,7 @@ parser_init_cxt(parser_state *p, mrb_ccontext *cxt)
p->capture_errors = cxt->capture_errors;
p->no_optimize = cxt->no_optimize;
p->no_ext_ops = cxt->no_ext_ops;
+ p->no_return_value = cxt->no_return_value;
p->upper = cxt->upper;
if (cxt->partial_hook) {
p->cxt = cxt;
@@ -6627,20 +7490,23 @@ parser_update_cxt(parser_state *p, mrb_ccontext *cxt)
if (!cxt) return;
if (!p->tree) return;
- if (intn(p->tree->car) != NODE_SCOPE) return;
- n0 = n = p->tree->cdr->car;
+ if (!node_type_p(p->tree, NODE_SCOPE)) return;
+
+ /* Extract locals from variable-sized NODE_SCOPE */
+ struct mrb_ast_scope_node *scope = scope_node(p->tree);
+ n0 = n = scope->locals;
while (n) {
i++;
n = n->cdr;
}
- cxt->syms = (mrb_sym*)mrb_realloc(p->mrb, cxt->syms, i*sizeof(mrb_sym));
+ cxt->syms = (mrb_sym*)mrbc_realloc(cxt->syms, i*sizeof(mrb_sym));
cxt->slen = i;
for (i=0, n=n0; n; i++,n=n->cdr) {
- cxt->syms[i] = sym(n->car);
+ cxt->syms[i] = node_to_sym(n->car);
}
}
-void mrb_parser_dump(mrb_state *mrb, node *tree, int offset);
+static void dump_node(mrb_state *mrb, node *tree, int offset);
MRB_API void
mrb_parser_parse(parser_state *p, mrb_ccontext *c)
@@ -6666,7 +7532,7 @@ mrb_parser_parse(parser_state *p, mrb_ccontext *c)
}
parser_update_cxt(p, c);
if (c && c->dump_result) {
- mrb_parser_dump(p->mrb, p->tree, 0);
+ dump_node(p->mrb, p->tree, 0);
}
}
MRB_CATCH(p->mrb->jmp) {
@@ -6684,13 +7550,13 @@ mrb_parser_parse(parser_state *p, mrb_ccontext *c)
MRB_API parser_state*
mrb_parser_new(mrb_state *mrb)
{
- mrb_mempool *pool;
+ mempool *pool;
parser_state *p;
static const parser_state parser_state_zero = { 0 };
- pool = mrb_mempool_open(mrb);
+ pool = mempool_open();
if (!pool) return NULL;
- p = (parser_state*)mrb_mempool_alloc(pool, sizeof(parser_state));
+ p = (parser_state*)mempool_alloc(pool, sizeof(parser_state));
if (!p) return NULL;
*p = parser_state_zero;
@@ -6726,23 +7592,26 @@ mrb_parser_new(mrb_state *mrb)
MRB_API void
mrb_parser_free(parser_state *p) {
if (p->tokbuf != p->buf) {
- mrb_free(p->mrb, p->tokbuf);
+ mrbc_free(p->tokbuf);
}
- mrb_mempool_close(p->pool);
+ mempool_close(p->pool);
}
MRB_API mrb_ccontext*
mrb_ccontext_new(mrb_state *mrb)
{
- return (mrb_ccontext*)mrb_calloc(mrb, 1, sizeof(mrb_ccontext));
+ static const mrb_ccontext cc_zero = { 0 };
+ mrb_ccontext *cc = (mrb_ccontext*)mrbc_malloc(sizeof(mrb_ccontext));
+ *cc = cc_zero;
+ return cc;
}
MRB_API void
mrb_ccontext_free(mrb_state *mrb, mrb_ccontext *cxt)
{
- mrb_free(mrb, cxt->filename);
- mrb_free(mrb, cxt->syms);
- mrb_free(mrb, cxt);
+ mrbc_free(cxt->filename);
+ mrbc_free(cxt->syms);
+ mrbc_free(cxt);
}
MRB_API const char*
@@ -6750,12 +7619,12 @@ mrb_ccontext_filename(mrb_state *mrb, mrb_ccontext *c, const char *s)
{
if (s) {
size_t len = strlen(s);
- char *p = (char*)mrb_malloc_simple(mrb, len + 1);
+ char *p = (char*)mrbc_malloc(len + 1);
if (p == NULL) return NULL;
memcpy(p, s, len + 1);
if (c->filename) {
- mrb_free(mrb, c->filename);
+ mrbc_free(c->filename);
}
c->filename = p;
}
@@ -6763,17 +7632,17 @@ mrb_ccontext_filename(mrb_state *mrb, mrb_ccontext *c, const char *s)
}
MRB_API void
-mrb_ccontext_partial_hook(mrb_state *mrb, mrb_ccontext *c, int (*func)(struct mrb_parser_state*), void *data)
+mrb_ccontext_partial_hook(mrb_ccontext *c, int (*func)(struct mrb_parser_state*), void *data)
{
c->partial_hook = func;
c->partial_data = data;
}
MRB_API void
-mrb_ccontext_cleanup_local_variables(mrb_state *mrb, mrb_ccontext *c)
+mrb_ccontext_cleanup_local_variables(mrb_ccontext *c)
{
if (c->syms) {
- mrb_free(mrb, c->syms);
+ mrbc_free(c->syms);
c->syms = NULL;
c->slen = 0;
}
@@ -6971,15 +7840,10 @@ mrb_load_detect_file_cxt(mrb_state *mrb, FILE *fp, mrb_ccontext *c)
return mrb_load_exec(mrb, mrb_parse_file_continue(mrb, fp, leading.b, bufsize, c), c);
}
else {
- mrb_int binsize;
- uint8_t *bin;
- mrb_value bin_obj = mrb_nil_value(); /* temporary string object */
- mrb_value result;
-
- binsize = bin_to_uint32(leading.h.binary_size);
- bin_obj = mrb_str_new(mrb, NULL, binsize);
- bin = (uint8_t*)RSTRING_PTR(bin_obj);
- if ((size_t)binsize > bufsize) {
+ mrb_int binsize = bin_to_uint32(leading.h.binary_size);
+ mrb_value bin_obj = mrb_str_new(mrb, NULL, binsize);
+ uint8_t *bin = (uint8_t*)RSTRING_PTR(bin_obj);
+ if ((size_t)binsize > bufsize) {
memcpy(bin, leading.b, bufsize);
if (fread(bin + bufsize, binsize - bufsize, 1, fp) == 0) {
binsize = bufsize;
@@ -6987,7 +7851,7 @@ mrb_load_detect_file_cxt(mrb_state *mrb, FILE *fp, mrb_ccontext *c)
}
}
- result = mrb_load_irep_buf_cxt(mrb, bin, binsize, c);
+ mrb_value result = mrb_load_irep_buf_cxt(mrb, bin, binsize, c);
if (mrb_string_p(bin_obj)) mrb_str_resize(mrb, bin_obj, 0);
return result;
}
@@ -7021,9 +7885,9 @@ mrb_load_string(mrb_state *mrb, const char *s)
#ifndef MRB_NO_STDIO
static void
-dump_prefix(node *tree, int offset)
+dump_prefix(int offset, uint16_t lineno)
{
- printf("%05d ", tree->lineno);
+ printf("%05d ", lineno);
while (offset--) {
putc(' ', stdout);
putc(' ', stdout);
@@ -7034,56 +7898,60 @@ static void
dump_recur(mrb_state *mrb, node *tree, int offset)
{
while (tree) {
- mrb_parser_dump(mrb, tree->car, offset);
+ dump_node(mrb, tree->car, offset);
tree = tree->cdr;
}
}
static void
-dump_args(mrb_state *mrb, node *n, int offset)
+dump_locals(mrb_state *mrb, node *tree, int offset, uint16_t lineno)
{
- 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;
+ if (!tree || (!tree->car && !tree->cdr)) return;
- while (n2) {
- dump_prefix(n2, offset+2);
- printf("%s=\n", mrb_sym_name(mrb, sym(n2->car->car)));
- mrb_parser_dump(mrb, n2->car->cdr, offset+3);
- n2 = n2->cdr;
+ dump_prefix(offset, lineno);
+ printf("locals:\n");
+ dump_prefix(offset+1, lineno);
+ while (tree) {
+ if (tree->car) {
+ mrb_sym sym = node_to_sym(tree->car);
+ if (sym != 0) {
+ const char *name = mrb_sym_name(mrb, sym);
+ if (name && strlen(name) > 0 && name[0] != '!' && name[0] != '@' && name[0] != '$') {
+ printf(" %s", mrb_sym_dump(mrb, sym));
+ }
+ else {
+ printf(" (invalid symbol: %s)", name ? name : "(null)");
+ }
+ }
+ else {
+ printf(" (anonymous)");
}
}
+ tree = tree->cdr;
}
- n = n->cdr;
- if (n->car) {
- mrb_sym rest = sym(n->car);
+ printf("\n");
+}
- dump_prefix(n, offset+1);
- if (rest == MRB_OPSYM(mul))
- printf("rest=*\n");
- else
- printf("rest=*%s\n", mrb_sym_name(mrb, rest));
+static void
+dump_cpath(mrb_state *mrb, node *tree, int offset, uint16_t lineno)
+{
+ dump_prefix(offset, lineno);
+ printf("cpath: ");
+ if (!tree) {
+ printf("(null)\n");
}
- n = n->cdr;
- if (n->car) {
- dump_prefix(n, offset+1);
- printf("post mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
+ else if (node_to_int(tree->car) == 0) {
+ printf("(null)\n");
}
-
- n = n->cdr;
- if (n) {
- mrb_assert(intn(n->car) == NODE_ARGS_TAIL);
- mrb_parser_dump(mrb, n, offset);
+ else if (node_to_int(tree->car) == 1) {
+ printf("Object\n");
+ }
+ else {
+ printf("\n");
+ dump_node(mrb, tree->car, offset+1);
}
+ dump_prefix(offset, lineno);
+ printf("name: %s\n", mrb_sym_dump(mrb, node_to_sym(tree->cdr)));
}
/*
@@ -7096,436 +7964,664 @@ static const char*
str_dump(mrb_state *mrb, const char *str, int len)
{
int ai = mrb_gc_arena_save(mrb);
- mrb_value s;
-# if INT_MAX > MRB_INT_MAX / 4
- /* check maximum length with "\xNN" character */
- if (len > MRB_INT_MAX / 4) {
- len = MRB_INT_MAX / 4;
- }
-# endif
- s = mrb_str_new(mrb, str, (mrb_int)len);
+ mrb_value s = mrb_str_new(mrb, str, (mrb_int)len);
s = mrb_str_dump(mrb, s);
mrb_gc_arena_restore(mrb, ai);
return RSTRING_PTR(s);
}
+
+static void
+dump_str(mrb_state *mrb, node *n, int offset, uint16_t lineno)
+{
+ while (n) {
+ dump_prefix(offset, lineno);
+ int len = node_to_int(n->car->car);
+ if (len >= 0) {
+ printf("str: %s\n", str_dump(mrb, (char*)n->car->cdr, len));
+ }
+ else {
+ printf("interpolation:\n");
+ dump_node(mrb, n->car->cdr, offset+1);
+ }
+ n = n->cdr;
+ }
+}
+
+static void
+dump_args(mrb_state *mrb, struct mrb_ast_args *args, int offset, uint16_t lineno)
+{
+ if (args->mandatory_args) {
+ dump_prefix(offset, lineno);
+ printf("mandatory args:\n");
+ dump_recur(mrb, args->mandatory_args, offset+1);
+ }
+ if (args->optional_args) {
+ dump_prefix(offset, lineno);
+ printf("optional args:\n");
+ {
+ node *n = args->optional_args;
+ while (n) {
+ dump_prefix(offset+1, lineno);
+ printf("%s=\n", mrb_sym_name(mrb, node_to_sym(n->car->car)));
+ dump_node(mrb, n->car->cdr, offset+2);
+ n = n->cdr;
+ }
+ }
+ }
+ if (args->rest_arg) {
+ mrb_sym rest = args->rest_arg;
+
+ dump_prefix(offset, lineno);
+ if (rest == MRB_OPSYM(mul))
+ printf("rest=*\n");
+ else
+ printf("rest=*%s\n", mrb_sym_name(mrb, rest));
+ }
+ if (args->post_mandatory_args) {
+ dump_prefix(offset, lineno);
+ printf("post mandatory args:\n");
+ dump_recur(mrb, args->post_mandatory_args, offset+1);
+ }
+ if (args->keyword_args) {
+ dump_prefix(offset, lineno);
+ printf("keyword args:\n");
+ {
+ node *n = args->keyword_args;
+ while (n) {
+ dump_prefix(offset+1, lineno);
+ printf("%s:\n", mrb_sym_name(mrb, node_to_sym(n->car->car)));
+ dump_node(mrb, n->car->cdr, offset+2);
+ n = n->cdr;
+ }
+ }
+ }
+ if (args->kwrest_arg) {
+ mrb_sym rest = args->kwrest_arg;
+
+ dump_prefix(offset, lineno);
+ if (rest == MRB_OPSYM(pow))
+ printf("kwrest=**\n");
+ else
+ printf("kwrest=**%s\n", mrb_sym_name(mrb, rest));
+ }
+ if (args->block_arg) {
+ mrb_sym blk = args->block_arg;
+
+ dump_prefix(offset, lineno);
+ if (blk == MRB_OPSYM(and))
+ printf("blk=&\n");
+ else if (blk == MRB_SYM(nil))
+ printf("blk=&nil\n");
+ else
+ printf("blk=&%s\n", mrb_sym_name(mrb, blk));
+ }
+}
+
+static void
+dump_callargs(mrb_state *mrb, node *n, int offset, uint16_t lineno)
+{
+ if (!n) return;
+
+ struct mrb_ast_callargs *args = (struct mrb_ast_callargs*)n;
+ if (args->regular_args) {
+ dump_prefix(offset+1, lineno);
+ printf("args:\n");
+ dump_recur(mrb, args->regular_args, offset+2);
+ }
+ if (args->keyword_args) {
+ dump_prefix(offset+1, lineno);
+ printf("kw_args:\n");
+ node *kw = args->keyword_args;
+ while (kw) {
+ dump_prefix(offset+2, lineno);
+ printf("key:\n");
+ if (node_to_sym(kw->car->car) == MRB_OPSYM(pow)) {
+ dump_prefix(offset+3, lineno);
+ printf("**:\n");
+ }
+ else {
+ dump_node(mrb, kw->car->car, offset+3);
+ }
+ dump_prefix(offset+2, lineno);
+ printf("value:\n");
+ dump_node(mrb, kw->car->cdr, offset+3);
+ kw = kw->cdr;
+ }
+ }
+ if (args->block_arg) {
+ dump_prefix(offset+1, lineno);
+ printf("block:\n");
+ dump_node(mrb, args->block_arg, offset+2);
+ }
+}
+
#endif
void
-mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
+dump_node(mrb_state *mrb, node *tree, int offset)
{
#ifndef MRB_NO_STDIO
- int nodetype;
+ enum node_type nodetype;
+ uint16_t lineno = 0;
if (!tree) return;
- again:
- dump_prefix(tree, offset);
- nodetype = intn(tree->car);
- tree = tree->cdr;
+
+ /* Extract line number from variable-sized node header */
+ if (node_type(tree) != NODE_LAST) {
+ lineno = ((struct mrb_ast_var_header*)tree)->lineno;
+ }
+
+ dump_prefix(offset, lineno);
+
+ /* All nodes are now variable-sized nodes with headers */
+ nodetype = node_type(tree);
+
switch (nodetype) {
+ /* Variable-sized node cases */
+ case NODE_SCOPE:
+ printf("NODE_SCOPE:\n");
+ if (scope_node(tree)->locals) {
+ dump_locals(mrb, scope_node(tree)->locals, offset+1, lineno);
+ }
+ if (scope_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, scope_node(tree)->body, offset+2);
+ }
+ break;
+
+ case NODE_INT:
+ printf("NODE_INT: %d\n", int_node(tree)->value);
+ break;
+
+ case NODE_BIGINT:
+ printf("NODE_BIGINT: %s (base %d)\n", bigint_node(tree)->string, bigint_node(tree)->base);
+ break;
+
+ case NODE_FLOAT:
+ printf("NODE_FLOAT: %s\n", float_node(tree)->value);
+ break;
+
+ case NODE_STR:
+ printf("NODE_STR:\n");
+ dump_str(mrb, str_node(tree)->list, offset+1, lineno);
+ break;
+
+ case NODE_XSTR:
+ printf("NODE_XSTR:\n");
+ dump_str(mrb, xstr_node(tree)->list, offset+1, lineno);
+ break;
+
+ case NODE_SYM:
+ printf("NODE_SYM: %s\n", mrb_sym_dump(mrb, sym_node(tree)->symbol));
+ break;
+
+ case NODE_DSYM:
+ printf("NODE_DSYM:\n");
+ dump_str(mrb, str_node(tree)->list, offset+1, lineno);
+ break;
+
+ case NODE_LVAR:
+ printf("NODE_LVAR: %s\n", mrb_sym_dump(mrb, var_node(tree)->symbol));
+ break;
+
+ case NODE_GVAR:
+ printf("NODE_GVAR: %s\n", mrb_sym_dump(mrb, var_node(tree)->symbol));
+ break;
+
+ case NODE_IVAR:
+ printf("NODE_IVAR: %s\n", mrb_sym_dump(mrb, var_node(tree)->symbol));
+ break;
+
+ case NODE_CVAR:
+ printf("NODE_CVAR: %s\n", mrb_sym_dump(mrb, var_node(tree)->symbol));
+ break;
+
+ case NODE_NVAR:
+ printf("NODE_NVAR: %d\n", nvar_node(tree)->num);
+ break;
+
+ case NODE_CONST:
+ printf("NODE_CONST: %s\n", mrb_sym_dump(mrb, var_node(tree)->symbol));
+ break;
+
+ case NODE_CALL:
+ printf("NODE_CALL: %s\n", mrb_sym_dump(mrb, call_node(tree)->method_name));
+ if (call_node(tree)->receiver) {
+ dump_prefix(offset+1, lineno);
+ printf("receiver:\n");
+ dump_node(mrb, call_node(tree)->receiver, offset+2);
+ }
+ if (call_node(tree)->args) {
+ dump_callargs(mrb, call_node(tree)->args, offset, lineno);
+ }
+ break;
+
+ case NODE_ARRAY:
+ printf("NODE_ARRAY:\n");
+ if (array_node(tree)->elements) {
+ dump_recur(mrb, array_node(tree)->elements, offset+1);
+ }
+ break;
+
+ case NODE_TRUE:
+ printf("NODE_TRUE\n");
+ break;
+
+ case NODE_FALSE:
+ printf("NODE_FALSE\n");
+ break;
+
+ case NODE_NIL:
+ printf("NODE_NIL\n");
+ break;
+
+ case NODE_SELF:
+ printf("NODE_SELF\n");
+ break;
+
+ case NODE_IF:
+ printf("NODE_IF:\n");
+ if (if_node(tree)->condition) {
+ dump_prefix(offset+1, lineno);
+ printf("cond:\n");
+ dump_node(mrb, if_node(tree)->condition, offset+2);
+ }
+ if (if_node(tree)->then_body) {
+ dump_prefix(offset+1, lineno);
+ printf("then:\n");
+ dump_node(mrb, if_node(tree)->then_body, offset+2);
+ }
+ if (if_node(tree)->else_body) {
+ dump_prefix(offset+1, lineno);
+ printf("else:\n");
+ dump_node(mrb, if_node(tree)->else_body, offset+2);
+ }
+ break;
+
+ case NODE_DEF:
+ printf("NODE_DEF: %s\n", mrb_sym_dump(mrb, def_node(tree)->name));
+ if (def_node(tree)->args) {
+ dump_args(mrb, sdef_node(tree)->args, offset+1, lineno);
+ }
+ if (def_node(tree)->locals) {
+ dump_locals(mrb, def_node(tree)->locals, offset+1, lineno);
+ }
+ if (def_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, def_node(tree)->body, offset+2);
+ }
+ break;
+
+ case NODE_ASGN:
+ printf("NODE_ASGN:\n");
+ if (asgn_node(tree)->lhs) {
+ dump_prefix(offset+1, lineno);
+ printf("lhs:\n");
+ dump_node(mrb, asgn_node(tree)->lhs, offset+2);
+ }
+ if (asgn_node(tree)->rhs) {
+ dump_prefix(offset+1, lineno);
+ printf("rhs:\n");
+ dump_node(mrb, asgn_node(tree)->rhs, offset+2);
+ }
+ break;
+
+ case NODE_MASGN:
+ case NODE_MARG:
+ printf("%s:\n", node_type(tree) == NODE_MASGN ? "NODE_MASGN" : "NODE_MARG");
+ /* Handle pre-splat variables */
+ if (masgn_node(tree)->pre) {
+ dump_prefix(offset+1, lineno);
+ printf("pre:\n");
+ dump_recur(mrb, masgn_node(tree)->pre, offset+2);
+ }
+ /* Handle splat variable (can be -1 sentinel for anonymous splat) */
+ if (masgn_node(tree)->rest) {
+ if ((intptr_t)masgn_node(tree)->rest == -1) {
+ dump_prefix(offset+1, lineno);
+ printf("rest: *<anonymous>\n");
+ }
+ else {
+ dump_prefix(offset+1, lineno);
+ printf("rest:\n");
+ dump_node(mrb, masgn_node(tree)->rest, offset+2);
+ }
+ }
+ /* Handle post-splat variables */
+ if (masgn_node(tree)->post) {
+ dump_prefix(offset+1, lineno);
+ printf("post:\n");
+ dump_recur(mrb, masgn_node(tree)->post, offset+2);
+ }
+ if (masgn_node(tree)->rhs) {
+ dump_prefix(offset+1, lineno);
+ printf("rhs:\n");
+ dump_node(mrb, masgn_node(tree)->rhs, offset+2);
+ }
+ break;
+
+ case NODE_RETURN:
+ printf("NODE_RETURN:\n");
+ if (return_node(tree)->args) {
+ dump_node(mrb, return_node(tree)->args, offset);
+ }
+ break;
+
+ case NODE_BREAK:
+ printf("NODE_BREAK:\n");
+ if (break_node(tree)->value) {
+ dump_prefix(offset+1, lineno);
+ printf("value:\n");
+ dump_node(mrb, break_node(tree)->value, offset+2);
+ }
+ break;
+
+ case NODE_NEXT:
+ printf("NODE_NEXT:\n");
+ if (next_node(tree)->value) {
+ dump_prefix(offset+1, lineno);
+ printf("value:\n");
+ dump_node(mrb, next_node(tree)->value, offset+2);
+ }
+ break;
+
+ case NODE_NEGATE:
+ printf("NODE_NEGATE:\n");
+ if (negate_node(tree)->operand) {
+ dump_prefix(offset+1, lineno);
+ printf("operand:\n");
+ dump_node(mrb, negate_node(tree)->operand, offset+2);
+ }
+ break;
+
+ case NODE_STMTS:
+ printf("NODE_STMTS:\n");
+ if (stmts_node(tree)->stmts) {
+ dump_recur(mrb, stmts_node(tree)->stmts, offset+1);
+ }
+ break;
+
case NODE_BEGIN:
printf("NODE_BEGIN:\n");
- dump_recur(mrb, tree, offset+1);
+ if (begin_node(tree)->body) {
+ dump_node(mrb, begin_node(tree)->body, offset+1);
+ }
break;
case NODE_RESCUE:
printf("NODE_RESCUE:\n");
- if (tree->car) {
- dump_prefix(tree, offset+1);
+ if (rescue_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
printf("body:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
+ dump_node(mrb, rescue_node(tree)->body, offset+2);
}
- tree = tree->cdr;
- if (tree->car) {
- node *n2 = tree->car;
-
- dump_prefix(n2, offset+1);
+ if (rescue_node(tree)->rescue_clauses) {
+ node *n2 = rescue_node(tree)->rescue_clauses;
+ dump_prefix(offset+1, lineno);
printf("rescue:\n");
while (n2) {
node *n3 = n2->car;
if (n3->car) {
- dump_prefix(n2, offset+2);
+ dump_prefix(offset+2, lineno);
printf("handle classes:\n");
dump_recur(mrb, n3->car, offset+3);
}
if (n3->cdr->car) {
- dump_prefix(n3, offset+2);
+ dump_prefix(offset+2, lineno);
printf("exc_var:\n");
- mrb_parser_dump(mrb, n3->cdr->car, offset+3);
+ dump_node(mrb, n3->cdr->car, offset+3);
}
if (n3->cdr->cdr->car) {
- dump_prefix(n3, offset+2);
+ dump_prefix(offset+2, lineno);
printf("rescue body:\n");
- mrb_parser_dump(mrb, n3->cdr->cdr->car, offset+3);
+ dump_node(mrb, n3->cdr->cdr->car, offset+3);
}
n2 = n2->cdr;
}
}
- tree = tree->cdr;
- if (tree->car) {
- dump_prefix(tree, offset+1);
+ if (rescue_node(tree)->else_clause) {
+ dump_prefix(offset+1, lineno);
printf("else:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
+ dump_node(mrb, rescue_node(tree)->else_clause, offset+2);
}
break;
case NODE_ENSURE:
printf("NODE_ENSURE:\n");
- dump_prefix(tree, offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- dump_prefix(tree, offset+1);
- printf("ensure:\n");
- mrb_parser_dump(mrb, tree->cdr->cdr, offset+2);
+ if (ensure_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, ensure_node(tree)->body, offset+2);
+ }
+ if (ensure_node(tree)->ensure_clause) {
+ dump_prefix(offset+1, lineno);
+ printf("ensure:\n");
+ dump_node(mrb, ensure_node(tree)->ensure_clause, offset+2);
+ }
break;
case NODE_LAMBDA:
printf("NODE_LAMBDA:\n");
- dump_prefix(tree, offset+1);
goto block;
case NODE_BLOCK:
- block:
printf("NODE_BLOCK:\n");
- tree = tree->cdr;
- if (tree->car) {
- dump_args(mrb, tree->car, offset+1);
+ block:
+ if (block_node(tree)->locals) {
+ dump_locals(mrb, block_node(tree)->locals, offset+1, lineno);
}
- dump_prefix(tree, offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->cdr->car, offset+2);
- break;
-
- case NODE_IF:
- printf("NODE_IF:\n");
- dump_prefix(tree, offset+1);
- printf("cond:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- dump_prefix(tree, offset+1);
- printf("then:\n");
- mrb_parser_dump(mrb, tree->cdr->car, offset+2);
- if (tree->cdr->cdr->car) {
- dump_prefix(tree, offset+1);
- printf("else:\n");
- mrb_parser_dump(mrb, tree->cdr->cdr->car, offset+2);
+ if (block_node(tree)->args) {
+ dump_args(mrb, block_node(tree)->args, offset+1, lineno);
}
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, block_node(tree)->body, offset+2);
break;
case NODE_AND:
printf("NODE_AND:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- mrb_parser_dump(mrb, tree->cdr, offset+1);
+ dump_node(mrb, and_node(tree)->left, offset+1);
+ dump_node(mrb, and_node(tree)->right, offset+1);
break;
case NODE_OR:
printf("NODE_OR:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- mrb_parser_dump(mrb, tree->cdr, offset+1);
+ dump_node(mrb, or_node(tree)->left, offset+1);
+ dump_node(mrb, or_node(tree)->right, offset+1);
break;
case NODE_CASE:
printf("NODE_CASE:\n");
- if (tree->car) {
- mrb_parser_dump(mrb, tree->car, offset+1);
- }
- tree = tree->cdr;
- while (tree) {
- dump_prefix(tree, offset+1);
- printf("case:\n");
- dump_recur(mrb, tree->car->car, offset+2);
- dump_prefix(tree, offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->car->cdr, offset+2);
- tree = tree->cdr;
+ if (case_node(tree)->value) {
+ dump_prefix(offset+1, lineno);
+ printf("value:\n");
+ dump_node(mrb, case_node(tree)->value, offset+2);
+ }
+ if (case_node(tree)->body) {
+ node *when_node = case_node(tree)->body;
+ while (when_node) {
+ dump_prefix(offset+1, lineno);
+ printf("when:\n");
+ node *when_clause = when_node->car;
+ if (when_clause && when_clause->car) {
+ dump_prefix(offset+2, lineno);
+ printf("cond:\n");
+ dump_recur(mrb, when_clause->car, offset+3);
+ }
+ if (when_clause && when_clause->cdr) {
+ dump_prefix(offset+2, lineno);
+ printf("body:\n");
+ dump_node(mrb, when_clause->cdr, offset+3);
+ }
+ when_node = when_node->cdr;
+ }
}
break;
case NODE_WHILE:
printf("NODE_WHILE:\n");
- dump_prefix(tree, offset+1);
- printf("cond:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- dump_prefix(tree, offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->cdr, offset+2);
- break;
-
+ goto dump_loop_node;
case NODE_UNTIL:
printf("NODE_UNTIL:\n");
- dump_prefix(tree, offset+1);
+ goto dump_loop_node;
+ case NODE_WHILE_MOD:
+ printf("NODE_WHILE_MOD:\n");
+ goto dump_loop_node;
+ case NODE_UNTIL_MOD:
+ printf("NODE_UNTIL_MOD:\n");
+
+ dump_loop_node:
+ dump_prefix(offset+1, lineno);
printf("cond:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- dump_prefix(tree, offset+1);
+ dump_node(mrb, while_node(tree)->condition, offset+2);
+ dump_prefix(offset+1, lineno);
printf("body:\n");
- mrb_parser_dump(mrb, tree->cdr, offset+2);
+ dump_node(mrb, while_node(tree)->body, offset+2);
break;
case NODE_FOR:
printf("NODE_FOR:\n");
- dump_prefix(tree, offset+1);
- printf("var:\n");
- {
- node *n2 = tree->car;
-
- if (n2->car) {
- dump_prefix(n2, offset+2);
- printf("pre:\n");
- dump_recur(mrb, n2->car, offset+3);
- }
- n2 = n2->cdr;
- if (n2) {
- if (n2->car) {
- dump_prefix(n2, offset+2);
- printf("rest:\n");
- mrb_parser_dump(mrb, n2->car, offset+3);
- }
- n2 = n2->cdr;
- if (n2) {
- if (n2->car) {
- dump_prefix(n2, offset+2);
- printf("post:\n");
- dump_recur(mrb, n2->car, offset+3);
+ if (for_node(tree)->var) {
+ dump_prefix(offset+1, lineno);
+ printf("var:\n");
+ /* FOR_NODE_VAR structure:
+ * var_list->car: cons-list of pre-splat variables
+ * var_list->cdr->car: splat varnode (not a cons-list)
+ * var_list->cdr->cdr->car: cons-list of post-splat variables */
+ node *var_list = for_node(tree)->var;
+ if (var_list) {
+ dump_recur(mrb, var_list->car, offset+2);
+ if (var_list && var_list->cdr) {
+ /* Second element is a varnode, not a cons-list */
+ dump_prefix(offset+1, lineno);
+ printf("splat var:\n");
+ dump_node(mrb, var_list->cdr->car, offset+2);
+ if (var_list->cdr->cdr) {
+ /* Third element is a cons-list of post-splat variables */
+ dump_prefix(offset+1, lineno);
+ printf("post var:\n");
+ dump_recur(mrb, var_list->cdr->cdr->car, offset+2);
}
}
}
}
- tree = tree->cdr;
- dump_prefix(tree, offset+1);
- printf("in:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- tree = tree->cdr;
- dump_prefix(tree, offset+1);
- printf("do:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- break;
-
- case NODE_SCOPE:
- printf("NODE_SCOPE:\n");
- {
- node *n2 = tree->car;
- mrb_bool first_lval = TRUE;
-
- if (n2 && (n2->car || n2->cdr)) {
- dump_prefix(n2, offset+1);
- printf("local variables:\n");
- dump_prefix(n2, offset+2);
- while (n2) {
- if (n2->car) {
- if (!first_lval) printf(", ");
- printf("%s", mrb_sym_name(mrb, sym(n2->car)));
- first_lval = FALSE;
- }
- n2 = n2->cdr;
- }
- printf("\n");
- }
+ if (for_node(tree)->iterable) {
+ dump_prefix(offset+1, lineno);
+ printf("iterable:\n");
+ dump_node(mrb, for_node(tree)->iterable, offset+2);
}
- tree = tree->cdr;
- offset++;
- goto again;
-
- case NODE_FCALL:
- case NODE_CALL:
- case NODE_SCALL:
- switch (nodetype) {
- case NODE_FCALL:
- printf("NODE_FCALL:\n"); break;
- case NODE_CALL:
- printf("NODE_CALL(.):\n"); break;
- case NODE_SCALL:
- printf("NODE_SCALL(&.):\n"); break;
- default:
- break;
- }
- mrb_parser_dump(mrb, tree->car, offset+1);
- dump_prefix(tree, offset+1);
- printf("method='%s' (%d)\n",
- mrb_sym_dump(mrb, sym(tree->cdr->car)),
- intn(tree->cdr->car));
- tree = tree->cdr->cdr->car;
- if (tree) {
- dump_prefix(tree, offset+1);
- printf("args:\n");
- dump_recur(mrb, tree->car, offset+2);
- if (tree->cdr) {
- if (tree->cdr->car) {
- dump_prefix(tree, offset+1);
- printf("kwargs:\n");
- mrb_parser_dump(mrb, tree->cdr->car, offset+2);
- }
- if (tree->cdr->cdr) {
- dump_prefix(tree, offset+1);
- printf("block:\n");
- mrb_parser_dump(mrb, tree->cdr->cdr, offset+2);
- }
- }
+ if (for_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, for_node(tree)->body, offset+2);
}
break;
case NODE_DOT2:
printf("NODE_DOT2:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- mrb_parser_dump(mrb, tree->cdr, offset+1);
+ {
+ if (dot2_node(tree)->left) {
+ dump_prefix(offset+1, lineno);
+ printf("left:\n");
+ dump_node(mrb, dot2_node(tree)->left, offset+2);
+ }
+ if (dot2_node(tree)->right) {
+ dump_prefix(offset+1, lineno);
+ printf("right:\n");
+ dump_node(mrb, dot2_node(tree)->right, offset+2);
+ }
+ }
break;
case NODE_DOT3:
printf("NODE_DOT3:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- mrb_parser_dump(mrb, tree->cdr, offset+1);
+ {
+ if (dot3_node(tree)->left) {
+ dump_prefix(offset+1, lineno);
+ printf("left:\n");
+ dump_node(mrb, dot3_node(tree)->left, offset+2);
+ }
+ if (dot3_node(tree)->right) {
+ dump_prefix(offset+1, lineno);
+ printf("right:\n");
+ dump_node(mrb, dot3_node(tree)->right, offset+2);
+ }
+ }
break;
case NODE_COLON2:
printf("NODE_COLON2:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- dump_prefix(tree, offset+1);
- printf("::%s\n", mrb_sym_name(mrb, sym(tree->cdr)));
+ if (colon2_node(tree)->base) {
+ dump_prefix(offset+1, lineno);
+ printf("base:\n");
+ dump_node(mrb, colon2_node(tree)->base, offset+2);
+ }
+ dump_prefix(offset+1, lineno);
+ printf("name: %s\n", mrb_sym_name(mrb, colon2_node(tree)->name));
break;
case NODE_COLON3:
- printf("NODE_COLON3: ::%s\n", mrb_sym_name(mrb, sym(tree)));
- break;
-
- case NODE_ARRAY:
- printf("NODE_ARRAY:\n");
- dump_recur(mrb, tree, offset+1);
+ printf("NODE_COLON3: ::%s\n", mrb_sym_name(mrb, colon3_node(tree)->name));
break;
case NODE_HASH:
printf("NODE_HASH:\n");
- while (tree) {
- dump_prefix(tree, offset+1);
- printf("key:\n");
- mrb_parser_dump(mrb, tree->car->car, offset+2);
- dump_prefix(tree, offset+1);
- printf("value:\n");
- mrb_parser_dump(mrb, tree->car->cdr, offset+2);
- tree = tree->cdr;
- }
- break;
-
- case NODE_KW_HASH:
- printf("NODE_KW_HASH:\n");
- while (tree) {
- dump_prefix(tree, offset+1);
- printf("key:\n");
- mrb_parser_dump(mrb, tree->car->car, offset+2);
- dump_prefix(tree, offset+1);
- printf("value:\n");
- mrb_parser_dump(mrb, tree->car->cdr, offset+2);
- tree = tree->cdr;
- }
- break;
-
- case NODE_SPLAT:
- printf("NODE_SPLAT:\n");
- mrb_parser_dump(mrb, tree, offset+1);
- break;
-
- case NODE_ASGN:
- printf("NODE_ASGN:\n");
- dump_prefix(tree, offset+1);
- printf("lhs:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- dump_prefix(tree, offset+1);
- printf("rhs:\n");
- mrb_parser_dump(mrb, tree->cdr, offset+2);
- break;
-
- case NODE_MASGN:
- printf("NODE_MASGN:\n");
- dump_prefix(tree, offset+1);
- printf("mlhs:\n");
{
- node *n2 = tree->car;
-
- if (n2->car) {
- dump_prefix(tree, offset+2);
- printf("pre:\n");
- dump_recur(mrb, n2->car, offset+3);
- }
- n2 = n2->cdr;
- if (n2) {
- if (n2->car) {
- dump_prefix(n2, offset+2);
- printf("rest:\n");
- if (n2->car == nint(-1)) {
- dump_prefix(n2, offset+2);
- printf("(empty)\n");
- }
- else {
- mrb_parser_dump(mrb, n2->car, offset+3);
- }
+ node *pairs = hash_node(tree)->pairs;
+ while (pairs) {
+ dump_prefix(offset+1, lineno);
+ printf("key:\n");
+ if (node_to_sym(pairs->car->car) == MRB_OPSYM(pow)) {
+ dump_prefix(offset+2, lineno);
+ printf("**\n");
}
- n2 = n2->cdr;
- if (n2 && n2->car) {
- dump_prefix(n2, offset+2);
- printf("post:\n");
- dump_recur(mrb, n2->car, offset+3);
+ else {
+ dump_node(mrb, pairs->car->car, offset+2);
}
+ dump_prefix(offset+1, lineno);
+ printf("value:\n");
+ dump_node(mrb, pairs->car->cdr, offset+2);
+ pairs = pairs->cdr;
}
}
- dump_prefix(tree, offset+1);
- printf("rhs:\n");
- mrb_parser_dump(mrb, tree->cdr, offset+2);
+ break;
+
+ case NODE_SPLAT:
+ printf("NODE_SPLAT:\n");
+ dump_node(mrb, splat_node(tree)->value, offset+1);
break;
case NODE_OP_ASGN:
printf("NODE_OP_ASGN:\n");
- dump_prefix(tree, offset+1);
+ dump_prefix(offset+1, lineno);
printf("lhs:\n");
- mrb_parser_dump(mrb, tree->car, offset+2);
- tree = tree->cdr;
- dump_prefix(tree, offset+1);
- printf("op='%s' (%d)\n", mrb_sym_name(mrb, sym(tree->car)), intn(tree->car));
- tree = tree->cdr;
- mrb_parser_dump(mrb, tree->car, offset+1);
+ dump_node(mrb, op_asgn_node(tree)->lhs, offset+2);
+ dump_prefix(offset+1, lineno);
+ printf("op='%s' (%d)\n", mrb_sym_name(mrb, op_asgn_node(tree)->op), (int)op_asgn_node(tree)->op);
+ dump_node(mrb, op_asgn_node(tree)->rhs, offset+1);
break;
case NODE_SUPER:
printf("NODE_SUPER:\n");
- if (tree) {
- dump_prefix(tree, offset+1);
- printf("args:\n");
- dump_recur(mrb, tree->car, offset+2);
- if (tree->cdr) {
- dump_prefix(tree, offset+1);
- printf("block:\n");
- mrb_parser_dump(mrb, tree->cdr, offset+2);
- }
+ if (super_node(tree)->args) {
+ dump_callargs(mrb, super_node(tree)->args, offset, lineno);
}
break;
case NODE_ZSUPER:
printf("NODE_ZSUPER:\n");
- if (tree) {
- dump_prefix(tree, offset+1);
- printf("args:\n");
- dump_recur(mrb, tree->car, offset+2);
- if (tree->cdr) {
- dump_prefix(tree, offset+1);
- printf("block:\n");
- mrb_parser_dump(mrb, tree->cdr, offset+2);
- }
+ if (super_node(tree)->args) {
+ dump_callargs(mrb, super_node(tree)->args, offset, lineno);
}
break;
- case NODE_RETURN:
- printf("NODE_RETURN:\n");
- mrb_parser_dump(mrb, tree, offset+1);
- break;
-
case NODE_YIELD:
printf("NODE_YIELD:\n");
- dump_recur(mrb, tree, offset+1);
- break;
-
- case NODE_BREAK:
- printf("NODE_BREAK:\n");
- mrb_parser_dump(mrb, tree, offset+1);
- break;
-
- case NODE_NEXT:
- printf("NODE_NEXT:\n");
- mrb_parser_dump(mrb, tree, offset+1);
+ if (yield_node(tree)->args) {
+ dump_callargs(mrb, yield_node(tree)->args, offset, lineno);
+ }
break;
case NODE_REDO:
@@ -7536,159 +8632,81 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
printf("NODE_RETRY\n");
break;
- case NODE_LVAR:
- printf("NODE_LVAR %s\n", mrb_sym_name(mrb, sym(tree)));
- break;
-
- case NODE_GVAR:
- printf("NODE_GVAR %s\n", mrb_sym_name(mrb, sym(tree)));
- break;
-
- case NODE_IVAR:
- printf("NODE_IVAR %s\n", mrb_sym_name(mrb, sym(tree)));
- break;
-
- case NODE_CVAR:
- printf("NODE_CVAR %s\n", mrb_sym_name(mrb, sym(tree)));
- break;
-
- case NODE_NVAR:
- printf("NODE_NVAR %d\n", intn(tree));
- break;
-
- case NODE_CONST:
- printf("NODE_CONST %s\n", mrb_sym_name(mrb, sym(tree)));
- break;
-
- case NODE_MATCH:
- printf("NODE_MATCH:\n");
- dump_prefix(tree, offset + 1);
- printf("lhs:\n");
- mrb_parser_dump(mrb, tree->car, offset + 2);
- dump_prefix(tree, offset + 1);
- printf("rhs:\n");
- mrb_parser_dump(mrb, tree->cdr, offset + 2);
- break;
-
case NODE_BACK_REF:
- printf("NODE_BACK_REF: $%c\n", intn(tree));
+ printf("NODE_BACK_REF: $%c\n", node_to_int(tree));
break;
case NODE_NTH_REF:
- printf("NODE_NTH_REF: $%d\n", intn(tree));
- break;
-
- case NODE_ARG:
- printf("NODE_ARG %s\n", mrb_sym_name(mrb, sym(tree)));
+ printf("NODE_NTH_REF: $%d\n", node_to_int(tree));
break;
case NODE_BLOCK_ARG:
printf("NODE_BLOCK_ARG:\n");
- mrb_parser_dump(mrb, tree, offset+1);
- break;
-
- case NODE_INT:
- printf("NODE_INT %s base %d\n", (char*)tree->car, intn(tree->cdr->car));
- break;
-
- case NODE_FLOAT:
- printf("NODE_FLOAT %s\n", (char*)tree);
- break;
-
- case NODE_NEGATE:
- printf("NODE_NEGATE:\n");
- mrb_parser_dump(mrb, tree, offset+1);
- break;
-
- case NODE_STR:
- printf("NODE_STR %s len %d\n", str_dump(mrb, (char*)tree->car, intn(tree->cdr)), intn(tree->cdr));
- break;
-
- case NODE_DSTR:
- printf("NODE_DSTR:\n");
- dump_recur(mrb, tree, offset+1);
- break;
-
- case NODE_XSTR:
- printf("NODE_XSTR %s len %d\n", str_dump(mrb, (char*)tree->car, intn(tree->cdr)), intn(tree->cdr));
- break;
-
- case NODE_DXSTR:
- printf("NODE_DXSTR:\n");
- dump_recur(mrb, tree, offset+1);
+ dump_node(mrb, block_arg_node(tree)->value, offset+1);
break;
case NODE_REGX:
- printf("NODE_REGX /%s/\n", (char*)tree->car);
- if (tree->cdr->car) {
- dump_prefix(tree, offset+1);
- printf("opt: %s\n", (char*)tree->cdr->car);
+ printf("NODE_REGX:\n");
+ if (regx_node(tree)->list) {
+ dump_str(mrb, regx_node(tree)->list, offset+1, lineno);
}
- if (tree->cdr->cdr) {
- dump_prefix(tree, offset+1);
- printf("enc: %s\n", (char*)tree->cdr->cdr);
+ if (regx_node(tree)->flags) {
+ dump_prefix(offset+1, lineno);
+ printf("flags: %s\n", regx_node(tree)->flags);
}
- break;
-
- case NODE_DREGX:
- printf("NODE_DREGX:\n");
- dump_recur(mrb, tree->car, offset+1);
- dump_prefix(tree, offset+1);
- printf("tail: %s\n", (char*)tree->cdr->cdr->car);
- if (tree->cdr->cdr->cdr->car) {
- dump_prefix(tree, offset+1);
- printf("opt: %s\n", (char*)tree->cdr->cdr->cdr->car);
+ if (regx_node(tree)->encoding) {
+ dump_prefix(offset+1, lineno);
+ printf("encoding: %s\n", regx_node(tree)->encoding);
}
- if (tree->cdr->cdr->cdr->cdr) {
- dump_prefix(tree, offset+1);
- printf("enc: %s\n", (char*)tree->cdr->cdr->cdr->cdr);
- }
- break;
-
- case NODE_SYM:
- printf("NODE_SYM :%s (%d)\n", mrb_sym_dump(mrb, sym(tree)),
- intn(tree));
- break;
-
- case NODE_DSYM:
- printf("NODE_DSYM:\n");
- mrb_parser_dump(mrb, tree, offset+1);
break;
case NODE_WORDS:
printf("NODE_WORDS:\n");
- dump_recur(mrb, tree, offset+1);
+ if (words_node(tree)->args) {
+ node *list = words_node(tree)->args;
+ while (list && list->car) {
+ node *item = list->car;
+ if (item->car == 0 && item->cdr == 0) {
+ /* Skip separator (0 . 0) */
+ }
+ else if (item->car && item->cdr) {
+ /* String item: (len . str) */
+ dump_prefix(offset+1, lineno);
+ int len = node_to_int(item->car);
+ if (len >= 0 && len < 1000 && item->cdr) {
+ printf("word: \"%.*s\"\n", len, (char*)item->cdr);
+ }
+ }
+ list = list->cdr;
+ }
+ }
break;
case NODE_SYMBOLS:
printf("NODE_SYMBOLS:\n");
- dump_recur(mrb, tree, offset+1);
- break;
-
- case NODE_LITERAL_DELIM:
- printf("NODE_LITERAL_DELIM\n");
- 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");
+ if (symbols_node(tree)->args) {
+ node *list = symbols_node(tree)->args;
+ while (list && list->car) {
+ node *item = list->car;
+ if (item->car == 0 && item->cdr == 0) {
+ /* Skip separator (0 . 0) */
+ } else if (item->car && item->cdr) {
+ /* String item: (len . str) */
+ dump_prefix(offset+1, lineno);
+ int len = node_to_int(item->car);
+ if (len >= 0 && len < 1000 && item->cdr) {
+ printf("symbol: \"%.*s\"\n", len, (char*)item->cdr);
+ }
+ }
+ list = list->cdr;
+ }
+ }
break;
case NODE_ALIAS:
printf("NODE_ALIAS %s %s:\n",
- mrb_sym_dump(mrb, sym(tree->car)),
- mrb_sym_dump(mrb, sym(tree->cdr)));
+ mrb_sym_dump(mrb, node_to_sym(tree->car)),
+ mrb_sym_dump(mrb, node_to_sym(tree->cdr)));
break;
case NODE_UNDEF:
@@ -7696,7 +8714,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
{
node *t = tree;
while (t) {
- printf(" %s", mrb_sym_dump(mrb, sym(t->car)));
+ printf(" %s", mrb_sym_dump(mrb, node_to_sym(t->car)));
t = t->cdr;
}
}
@@ -7705,153 +8723,238 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
case NODE_CLASS:
printf("NODE_CLASS:\n");
- if (tree->car->car == nint(0)) {
- dump_prefix(tree, offset+1);
- printf(":%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
+ if (class_node(tree)->name) {
+ dump_cpath(mrb, module_node(tree)->name, offset+1, lineno);
}
- else if (tree->car->car == nint(1)) {
- dump_prefix(tree, offset+1);
- printf("::%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
- }
- else {
- mrb_parser_dump(mrb, tree->car->car, offset+1);
- dump_prefix(tree, offset+1);
- printf("::%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
- }
- if (tree->cdr->car) {
- dump_prefix(tree, offset+1);
+ if (class_node(tree)->superclass) {
+ dump_prefix(offset+1, lineno);
printf("super:\n");
- mrb_parser_dump(mrb, tree->cdr->car, offset+2);
+ dump_node(mrb, class_node(tree)->superclass, offset+2);
+ }
+ if (class_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, class_node(tree)->body->cdr, offset+2);
}
- dump_prefix(tree, offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->cdr->cdr->car->cdr, offset+2);
break;
case NODE_MODULE:
printf("NODE_MODULE:\n");
- if (tree->car->car == nint(0)) {
- dump_prefix(tree, offset+1);
- printf(":%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
+ if (module_node(tree)->name) {
+ dump_cpath(mrb, module_node(tree)->name, offset+1, lineno);
}
- else if (tree->car->car == nint(1)) {
- dump_prefix(tree, offset+1);
- printf("::%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
- }
- else {
- mrb_parser_dump(mrb, tree->car->car, offset+1);
- dump_prefix(tree, offset+1);
- printf("::%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
+ if (module_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, module_node(tree)->body->cdr, offset+2);
}
- dump_prefix(tree, offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2);
break;
case NODE_SCLASS:
printf("NODE_SCLASS:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- dump_prefix(tree, offset+1);
- printf("body:\n");
- mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2);
- break;
-
- case NODE_DEF:
- printf("NODE_DEF:\n");
- dump_prefix(tree, offset+1);
- printf("%s\n", mrb_sym_dump(mrb, sym(tree->car)));
- tree = tree->cdr;
- {
- node *n2 = tree->car;
- mrb_bool first_lval = TRUE;
-
- if (n2 && (n2->car || n2->cdr)) {
- dump_prefix(n2, offset+1);
- printf("local variables:\n");
- dump_prefix(n2, offset+2);
- while (n2) {
- if (n2->car) {
- if (!first_lval) printf(", ");
- printf("%s", mrb_sym_name(mrb, sym(n2->car)));
- first_lval = FALSE;
- }
- n2 = n2->cdr;
- }
- printf("\n");
- }
+ if (sclass_node(tree)->obj) {
+ dump_prefix(offset+1, lineno);
+ printf("obj:\n");
+ dump_node(mrb, sclass_node(tree)->obj, offset+2);
}
- tree = tree->cdr;
- if (tree->car) {
- dump_args(mrb, tree->car, offset);
+ if (sclass_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, sclass_node(tree)->body->cdr, offset+2);
}
- mrb_parser_dump(mrb, tree->cdr->car, offset+1);
break;
case NODE_SDEF:
- printf("NODE_SDEF:\n");
- mrb_parser_dump(mrb, tree->car, offset+1);
- tree = tree->cdr;
- dump_prefix(tree, offset+1);
- printf(":%s\n", mrb_sym_dump(mrb, sym(tree->car)));
- tree = tree->cdr->cdr;
- if (tree->car) {
- dump_args(mrb, tree->car, offset+1);
+ printf("NODE_SDEF: %s\n", mrb_sym_dump(mrb, def_node(tree)->name));
+ if (sdef_node(tree)->obj) {
+ dump_prefix(offset+1, lineno);
+ printf("recv:\n");
+ dump_node(mrb, sdef_node(tree)->obj, offset+2);
+ }
+ if (sdef_node(tree)->args) {
+ dump_args(mrb, sdef_node(tree)->args, offset+1, lineno);
+ }
+ if (sdef_node(tree)->locals) {
+ dump_locals(mrb, sdef_node(tree)->locals, offset+1, lineno);
+ }
+ if (sdef_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, sdef_node(tree)->body, offset+2);
}
- tree = tree->cdr;
- mrb_parser_dump(mrb, tree->car, offset+1);
break;
case NODE_POSTEXE:
printf("NODE_POSTEXE:\n");
- mrb_parser_dump(mrb, tree, offset+1);
+ dump_node(mrb, tree, offset+1);
break;
case NODE_HEREDOC:
- printf("NODE_HEREDOC (<<%s):\n", ((parser_heredoc_info*)tree)->term);
- dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1);
+ printf("NODE_HEREDOC:\n");
+ if (heredoc_node(tree)->info.term) {
+ dump_prefix(offset+1, lineno);
+ printf("terminator: \"%s\"\n", heredoc_node(tree)->info.term);
+ }
+ if (heredoc_node(tree)->info.doc) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_str(mrb, heredoc_node(tree)->info.doc, offset+2, lineno);
+ }
+ if (heredoc_node(tree)->info.allow_indent) {
+ dump_prefix(offset+1, lineno);
+ printf("allow_indent: true\n");
+ }
+ if (heredoc_node(tree)->info.remove_indent) {
+ dump_prefix(offset+1, lineno);
+ printf("remove_indent: true\n");
+ }
break;
- case NODE_ARGS_TAIL:
- printf("NODE_ARGS_TAIL:\n");
- {
- node *kws = tree->car;
-
- while (kws) {
- mrb_parser_dump(mrb, kws->car, offset+1);
- kws = kws->cdr;
+ case NODE_CASE_MATCH:
+ printf("NODE_CASE_MATCH:\n");
+ if (case_match_node(tree)->value) {
+ dump_prefix(offset+1, lineno);
+ printf("value:\n");
+ dump_node(mrb, case_match_node(tree)->value, offset+2);
+ }
+ if (case_match_node(tree)->in_clauses) {
+ node *in_clause = case_match_node(tree)->in_clauses;
+ while (in_clause) {
+ dump_node(mrb, in_clause->car, offset+1);
+ in_clause = in_clause->cdr;
}
}
- tree = tree->cdr;
- if (tree->car) {
- mrb_assert(intn(tree->car->car) == NODE_KW_REST_ARGS);
- mrb_parser_dump(mrb, tree->car, offset+1);
+ break;
+
+ case NODE_IN:
+ printf("NODE_IN:\n");
+ if (in_node(tree)->pattern) {
+ dump_prefix(offset+1, lineno);
+ printf("pattern:\n");
+ dump_node(mrb, in_node(tree)->pattern, offset+2);
}
- tree = tree->cdr;
- if (tree->car) {
- dump_prefix(tree, offset+1);
- printf("block='%s'\n", mrb_sym_name(mrb, sym(tree->car)));
+ if (in_node(tree)->guard) {
+ dump_prefix(offset+1, lineno);
+ printf("guard (%s):\n", in_node(tree)->guard_is_unless ? "unless" : "if");
+ dump_node(mrb, in_node(tree)->guard, offset+2);
+ }
+ if (in_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, in_node(tree)->body, offset+2);
}
break;
- case NODE_KW_ARG:
- printf("NODE_KW_ARG %s:\n", mrb_sym_name(mrb, sym(tree->car)));
- mrb_parser_dump(mrb, tree->cdr->car, offset + 1);
+ case NODE_PAT_VALUE:
+ printf("NODE_PAT_VALUE:\n");
+ if (pat_value_node(tree)->value) {
+ dump_node(mrb, pat_value_node(tree)->value, offset+1);
+ }
break;
- case NODE_KW_REST_ARGS:
- if (tree)
- printf("NODE_KW_REST_ARGS %s\n", mrb_sym_name(mrb, sym(tree)));
- else
- printf("NODE_KW_REST_ARGS\n");
+ case NODE_PAT_VAR:
+ if (pat_var_node(tree)->name) {
+ printf("NODE_PAT_VAR: %s\n", mrb_sym_dump(mrb, pat_var_node(tree)->name));
+ }
+ else {
+ printf("NODE_PAT_VAR: _ (wildcard)\n");
+ }
+ break;
+
+ case NODE_PAT_PIN:
+ printf("NODE_PAT_PIN: ^%s\n", mrb_sym_dump(mrb, pat_pin_node(tree)->name));
+ break;
+
+ case NODE_PAT_AS:
+ printf("NODE_PAT_AS: => %s\n", mrb_sym_dump(mrb, pat_as_node(tree)->name));
+ if (pat_as_node(tree)->pattern) {
+ dump_prefix(offset+1, lineno);
+ printf("pattern:\n");
+ dump_node(mrb, pat_as_node(tree)->pattern, offset+2);
+ }
+ break;
+
+ case NODE_PAT_ALT:
+ printf("NODE_PAT_ALT:\n");
+ if (pat_alt_node(tree)->left) {
+ dump_prefix(offset+1, lineno);
+ printf("left:\n");
+ dump_node(mrb, pat_alt_node(tree)->left, offset+2);
+ }
+ if (pat_alt_node(tree)->right) {
+ dump_prefix(offset+1, lineno);
+ printf("right:\n");
+ dump_node(mrb, pat_alt_node(tree)->right, offset+2);
+ }
+ break;
+
+ case NODE_PAT_ARRAY:
+ printf("NODE_PAT_ARRAY:\n");
+ if (pat_array_node(tree)->pre) {
+ dump_prefix(offset+1, lineno);
+ printf("pre:\n");
+ dump_recur(mrb, pat_array_node(tree)->pre, offset+2);
+ }
+ if (pat_array_node(tree)->rest) {
+ dump_prefix(offset+1, lineno);
+ if (pat_array_node(tree)->rest == (node*)-1) {
+ printf("rest: * (anonymous)\n");
+ }
+ else {
+ printf("rest:\n");
+ dump_node(mrb, pat_array_node(tree)->rest, offset+2);
+ }
+ }
+ if (pat_array_node(tree)->post) {
+ dump_prefix(offset+1, lineno);
+ printf("post:\n");
+ dump_recur(mrb, pat_array_node(tree)->post, offset+2);
+ }
+ break;
+
+ case NODE_PAT_HASH:
+ printf("NODE_PAT_HASH:\n");
+ if (pat_hash_node(tree)->pairs) {
+ dump_prefix(offset+1, lineno);
+ printf("pairs:\n");
+ dump_recur(mrb, pat_hash_node(tree)->pairs, offset+2);
+ }
+ if (pat_hash_node(tree)->rest) {
+ dump_prefix(offset+1, lineno);
+ if (pat_hash_node(tree)->rest == (node*)-1) {
+ printf("rest: **nil\n");
+ }
+ else {
+ printf("rest:\n");
+ dump_node(mrb, pat_hash_node(tree)->rest, offset+2);
+ }
+ }
+ break;
+
+ case NODE_MATCH_PAT:
+ printf("NODE_MATCH_PAT%s:\n", match_pat_node(tree)->raise_on_fail ? " (=>)" : " (in)");
+ dump_prefix(offset+1, lineno);
+ printf("value:\n");
+ dump_node(mrb, match_pat_node(tree)->value, offset+2);
+ dump_prefix(offset+1, lineno);
+ printf("pattern:\n");
+ dump_node(mrb, match_pat_node(tree)->pattern, offset+2);
break;
default:
- printf("node type: %d (0x%x)\n", nodetype, (unsigned)nodetype);
+ /* Fallback: unknown node type - skip like codegen.c does */
+ printf("unknown node type %d (0x%x)\n", nodetype, (unsigned)nodetype);
break;
}
#endif
}
+void
+mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
+{
+ dump_node(mrb, tree, offset);
+}
+
typedef mrb_bool mrb_parser_foreach_top_variable_func(mrb_state *mrb, mrb_sym sym, void *user);
void mrb_parser_foreach_top_variable(mrb_state *mrb, struct mrb_parser_state *p, mrb_parser_foreach_top_variable_func *func, void *user);
@@ -7859,11 +8962,15 @@ void
mrb_parser_foreach_top_variable(mrb_state *mrb, struct mrb_parser_state *p, mrb_parser_foreach_top_variable_func *func, void *user)
{
const mrb_ast_node *n = p->tree;
- if ((intptr_t)n->car == NODE_SCOPE) {
- n = n->cdr->car;
+ if (node_type_p((node*)n, NODE_SCOPE)) {
+ /* Extract locals from variable-sized NODE_SCOPE */
+ struct mrb_ast_scope_node *scope = scope_node(n);
+ n = scope->locals;
for (; n; n = n->cdr) {
- mrb_sym sym = sym(n->car);
- if (sym && !func(mrb, sym, user)) break;
+ mrb_sym sym = node_to_sym(n->car);
+ if (sym != 0) {
+ if (!func(mrb, sym, user)) break;
+ }
}
}
}
diff --git a/mrbgems/mruby-compiler/core/y.tab.c b/mrbgems/mruby-compiler/core/y.tab.c
new file mode 100644
index 0000000..098cad5
--- /dev/null
+++ b/mrbgems/mruby-compiler/core/y.tab.c
@@ -0,0 +1,16165 @@
+/* A Bison parser, made by Lrama 0.7.0. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
+ Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+ especially those whose name start with YY_ or yy_. They are
+ private implementation details that can be changed or removed. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output, and Bison version. */
+#define YYBISON 30802
+
+/* Bison version string. */
+#define YYBISON_VERSION "3.8.2"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+/* First part of user prologue. */
+#line 7 "mrbgems/mruby-compiler/core/parse.y"
+
+#undef PARSER_DEBUG
+#ifdef PARSER_DEBUG
+# define YYDEBUG 1
+#endif
+#define YYSTACK_USE_ALLOCA 1
+
+#include <ctype.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mruby.h>
+#include <mruby/compile.h>
+#include <mruby/proc.h>
+#include <mruby/error.h>
+#include <mruby/throw.h>
+#include <mruby/string.h>
+#include <mruby/dump.h>
+#include <mruby/internal.h>
+#include "node.h"
+
+#define YYLEX_PARAM p
+
+#define mrbc_malloc(s) mrb_basic_alloc_func(NULL,(s))
+#define mrbc_realloc(p,s) mrb_basic_alloc_func((p),(s))
+#define mrbc_free(p) mrb_basic_alloc_func((p),0)
+
+typedef mrb_ast_node node;
+typedef struct mrb_parser_state parser_state;
+typedef struct mrb_parser_heredoc_info parser_heredoc_info;
+
+static int yyparse(parser_state *p);
+static int yylex(void *lval, void *lp, parser_state *p);
+static void yyerror(void *lp, parser_state *p, const char *s);
+static void yywarning(parser_state *p, const char *s);
+static void backref_error(parser_state *p, node *n);
+static void void_expr_error(parser_state *p, node *n);
+static void tokadd(parser_state *p, int32_t c);
+static const char* tok(parser_state *p);
+static int toklen(parser_state *p);
+
+/* Forward declarations for variable-sized simple node functions */
+
+/* Forward declarations for variable-sized advanced node functions */
+
+/* Helper function to check node type for both traditional and variable-sized nodes */
+static mrb_bool node_type_p(node *n, enum node_type type);
+
+#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c))
+
+typedef unsigned int stack_type;
+
+#define BITSTACK_PUSH(stack, n) ((stack) = ((stack)<<1)|((n)&1))
+#define BITSTACK_POP(stack) ((stack) = (stack) >> 1)
+#define BITSTACK_LEXPOP(stack) ((stack) = ((stack) >> 1) | ((stack) & 1))
+#define BITSTACK_SET_P(stack) ((stack)&1)
+
+#define COND_PUSH(n) BITSTACK_PUSH(p->cond_stack, (n))
+#define COND_POP() BITSTACK_POP(p->cond_stack)
+#define COND_LEXPOP() BITSTACK_LEXPOP(p->cond_stack)
+#define COND_P() BITSTACK_SET_P(p->cond_stack)
+
+#define CMDARG_PUSH(n) BITSTACK_PUSH(p->cmdarg_stack, (n))
+#define CMDARG_POP() BITSTACK_POP(p->cmdarg_stack)
+#define CMDARG_LEXPOP() BITSTACK_LEXPOP(p->cmdarg_stack)
+#define CMDARG_P() BITSTACK_SET_P(p->cmdarg_stack)
+
+#define SET_LINENO(c,n) (((struct mrb_ast_var_header*)(c))->lineno = (n))
+
+#define NUM_SUFFIX_R (1<<0)
+#define NUM_SUFFIX_I (1<<1)
+
+static inline mrb_sym
+intern_cstr_gen(parser_state *p, const char *s)
+{
+ return mrb_intern_cstr(p->mrb, s);
+}
+#define intern_cstr(s) intern_cstr_gen(p,(s))
+
+static inline mrb_sym
+intern_gen(parser_state *p, const char *s, size_t len)
+{
+ return mrb_intern(p->mrb, s, len);
+}
+#define intern(s,len) intern_gen(p,(s),(len))
+
+#define intern_op(op) MRB_OPSYM(op)
+
+static mrb_sym
+intern_numparam_gen(parser_state *p, int num)
+{
+ char buf[3];
+ buf[0] = '_'; buf[1] = '0'+num; buf[2] = '\0';
+ return intern(buf, 2);
+}
+#define intern_numparam(n) intern_numparam_gen(p,(n))
+
+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 = mempool_alloc(p->pool, size);
+
+ if (!m) {
+ MRB_THROW(p->mrb->jmp);
+ }
+ return m;
+}
+
+#define parser_pfree(ptr) do { if (sizeof(node) <= sizeof(*(ptr))) cons_free((node*)ptr);} while (0)
+
+static node*
+cons_gen(parser_state *p, node *car, node *cdr)
+{
+ struct mrb_ast_node *c;
+
+ /* Try to reuse from free list first - only for 16-byte nodes */
+ if (p->cells) {
+ c = (struct mrb_ast_node*)p->cells;
+ p->cells = p->cells->cdr;
+ }
+ else {
+ c = (struct mrb_ast_node*)parser_palloc(p, sizeof(struct mrb_ast_node));
+ }
+ c->car = car;
+ c->cdr = cdr;
+ /* Don't initialize location fields for structure nodes - saves CPU */
+ return (node*)c;
+}
+
+/* Head-only location optimization: separate functions for head vs structure nodes */
+#define cons(a,b) cons_gen(p,(a),(b)) /* Structure nodes - no location */
+/* Initialize variable node header */
+static void
+init_var_header(struct mrb_ast_var_header *header, parser_state *p, enum node_type type)
+{
+ header->lineno = p->lineno;
+ header->filename_index = p->current_filename_index;
+ header->node_type = (uint8_t)type;
+
+ /* Handle file boundary edge case */
+ if (p->lineno == 0 && p->current_filename_index > 0) {
+ header->filename_index--;
+ }
+}
+
+/* Combined allocate + init header helper */
+static inline void*
+new_node(parser_state *p, size_t size, enum node_type type)
+{
+ void *n = parser_palloc(p, size);
+ init_var_header((struct mrb_ast_var_header*)n, p, type);
+ return n;
+}
+
+/* Type-safe macro wrapper for node allocation */
+#define NEW_NODE(type_name, node_type) \
+ (struct mrb_ast_##type_name##_node*)new_node(p, sizeof(struct mrb_ast_##type_name##_node), node_type)
+
+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*
+append_gen(parser_state *p, node *a, node *b)
+{
+ node *c = a;
+
+ if (!a) return b;
+ if (!b) return a;
+ while (c->cdr) {
+ c = c->cdr;
+ }
+ c->cdr = b;
+ return a;
+}
+#define append(a,b) append_gen(p,(a),(b))
+#define push(a,b) append_gen(p,(a),list1(b))
+
+static char*
+parser_strndup(parser_state *p, const char *s, size_t len)
+{
+ char *b = (char*)parser_palloc(p, len+1);
+
+ memcpy(b, s, len);
+ b[len] = '\0';
+ return b;
+}
+#undef strndup
+#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)
+
+static void
+dump_int(uint16_t i, char *s)
+{
+ char *p = s;
+ char *t = s;
+
+ while (i > 0) {
+ *p++ = (i % 10)+'0';
+ i /= 10;
+ }
+ if (p == s) *p++ = '0';
+ *p = 0;
+ p--; /* point the last char */
+ while (t < p) {
+ char c = *t;
+ *t++ = *p;
+ *p-- = c;
+ }
+}
+
+/* xxx ----------------------------- */
+
+static node*
+local_switch(parser_state *p)
+{
+ node *prev = p->locals;
+
+ p->locals = cons(0, 0);
+ return prev;
+}
+
+static void
+local_resume(parser_state *p, node *prev)
+{
+ p->locals = prev;
+}
+
+static void
+local_nest(parser_state *p)
+{
+ p->locals = cons(0, p->locals);
+}
+
+static void
+local_unnest(parser_state *p)
+{
+ if (p->locals) {
+ p->locals = p->locals->cdr;
+ }
+}
+
+static mrb_bool
+local_var_p(parser_state *p, mrb_sym sym)
+{
+ const struct RProc *u;
+ node *l = p->locals;
+
+ while (l) {
+ node *n = l->car;
+ while (n) {
+ if (node_to_sym(n->car) == sym) return TRUE;
+ n = n->cdr;
+ }
+ l = l->cdr;
+ }
+
+ u = p->upper;
+ while (u && !MRB_PROC_CFUNC_P(u)) {
+ const struct mrb_irep *ir = u->body.irep;
+ const mrb_sym *v = ir->lv;
+ int i;
+
+ if (v) {
+ for (i=0; i+1 < ir->nlocals; i++) {
+ if (v[i] == sym) return TRUE;
+ }
+ }
+ if (MRB_PROC_SCOPE_P(u)) break;
+ u = u->upper;
+ }
+ return FALSE;
+}
+
+static void
+local_add_f(parser_state *p, mrb_sym sym)
+{
+ if (p->locals) {
+ node *n = p->locals->car;
+ while (n) {
+ if (node_to_sym(n->car) == sym) {
+ mrb_int len;
+ const char* name = mrb_sym_name_len(p->mrb, sym, &len);
+ if (len > 0 && name[0] != '_') {
+ yyerror(NULL, p, "duplicated argument name");
+ return;
+ }
+ }
+ n = n->cdr;
+ }
+ p->locals->car = push(p->locals->car, sym_to_node(sym));
+ }
+}
+
+static void
+local_add(parser_state *p, mrb_sym sym)
+{
+ if (!local_var_p(p, sym)) {
+ local_add_f(p, sym);
+ }
+}
+
+/* allocate register for block */
+#define local_add_blk(p) local_add_f(p, 0)
+
+static void
+local_add_kw(parser_state *p, mrb_sym kwd)
+{
+ /* allocate register for keywords hash */
+ local_add_f(p, kwd ? kwd : intern_op(pow));
+}
+
+static node*
+locals_node(parser_state *p)
+{
+ return p->locals ? p->locals->car : NULL;
+}
+
+/* Helper function to check node type for both traditional and variable-sized nodes */
+static mrb_bool
+node_type_p(node *n, enum node_type type)
+{
+ if (!n) return FALSE;
+
+ /* Check if this is a variable-sized node */
+ struct mrb_ast_var_header *header = (struct mrb_ast_var_header*)n;
+ return ((enum node_type)header->node_type == type);
+}
+
+/* Helper functions for variable-sized node detection */
+static enum node_type
+node_type(node *n)
+{
+ if (!n) return (enum node_type)0;
+
+ /* Try to interpret as variable-sized node */
+ struct mrb_ast_var_header *header = (struct mrb_ast_var_header*)n;
+ enum node_type type = (enum node_type)header->node_type;
+
+ /* Validate that the node type is within valid range for variable-sized nodes */
+ if (type >= NODE_SCOPE && type < NODE_LAST) {
+ return type;
+ }
+
+ /* If node type is invalid, this is likely a cons-list node */
+ /* Return a special sentinel value to indicate cons-list fallback */
+ return NODE_LAST; /* Use NODE_LAST as sentinel for cons-list nodes */
+}
+
+static void
+nvars_nest(parser_state *p)
+{
+ p->nvars = cons(int_to_node(0), p->nvars);
+}
+
+static void
+nvars_block(parser_state *p)
+{
+ p->nvars = cons(int_to_node(-2), p->nvars);
+}
+
+static void
+nvars_unnest(parser_state *p)
+{
+ p->nvars = p->nvars->cdr;
+}
+
+/* struct: scope_node(locals, body) */
+static node*
+new_scope(parser_state *p, node *body)
+{
+ struct mrb_ast_scope_node *scope_node = NEW_NODE(scope, NODE_SCOPE);
+ scope_node->locals = locals_node(p);
+ scope_node->body = body;
+ return (node*)scope_node;
+}
+
+/* struct: stmts_node(stmts) - uses cons list */
+static node*
+new_stmts(parser_state *p, node *body)
+{
+ struct mrb_ast_stmts_node *n = NEW_NODE(stmts, NODE_STMTS);
+ n->stmts = body ? list1(body) : 0; /* Wrap single statement in cons-list */
+
+ return (node*)n;
+}
+
+/* Helper: push statement to stmts node */
+static node*
+stmts_push(parser_state *p, node *stmts, node *stmt)
+{
+ struct mrb_ast_stmts_node *n = stmts_node(stmts);
+ n->stmts = push(n->stmts, stmt);
+ return stmts;
+}
+
+/* struct: begin_node(body) */
+static node*
+new_begin(parser_state *p, node *body)
+{
+ struct mrb_ast_begin_node *begin_node = NEW_NODE(begin, NODE_BEGIN);
+ begin_node->body = body;
+ return (node*)begin_node;
+}
+
+#define newline_node(n) (n)
+
+/* struct: rescue_node(body, rescue_clauses, else_clause) */
+static node*
+new_rescue(parser_state *p, node *body, node *resq, node *els)
+{
+ struct mrb_ast_rescue_node *n = NEW_NODE(rescue, NODE_RESCUE);
+ n->body = body;
+ n->rescue_clauses = resq;
+ n->else_clause = els;
+
+ return (node*)n;
+}
+
+static node*
+new_mod_rescue(parser_state *p, node *body, node *resq)
+{
+ return new_rescue(p, body, list1(list3(0, 0, resq)), 0);
+}
+
+/* struct: ensure_node(body, ensure_clause) */
+static node*
+new_ensure(parser_state *p, node *a, node *b)
+{
+ struct mrb_ast_ensure_node *ensure_node = NEW_NODE(ensure, NODE_ENSURE);
+ ensure_node->body = a;
+ ensure_node->ensure_clause = b;
+ return (node*)ensure_node;
+}
+
+/* struct: nil_node() */
+static node*
+new_nil(parser_state *p)
+{
+ struct mrb_ast_nil_node *n = NEW_NODE(nil, NODE_NIL);
+
+ return (node*)n;
+}
+
+/* struct: true_node() */
+static node*
+new_true(parser_state *p)
+{
+ struct mrb_ast_true_node *n = NEW_NODE(true, NODE_TRUE);
+
+ return (node*)n;
+}
+
+/* struct: false_node() */
+static node*
+new_false(parser_state *p)
+{
+ struct mrb_ast_false_node *n = NEW_NODE(false, NODE_FALSE);
+
+ return (node*)n;
+}
+
+/* struct: alias_node(new_name, old_name) */
+static node*
+new_alias(parser_state *p, mrb_sym a, mrb_sym b)
+{
+ struct mrb_ast_alias_node *alias_node = NEW_NODE(alias, NODE_ALIAS);
+ alias_node->new_name = a;
+ alias_node->old_name = b;
+ return (node*)alias_node;
+}
+
+/* struct: if_node(cond, then_body, else_body) */
+static node*
+new_if(parser_state *p, node *condition, node *then_body, node *else_body)
+{
+ void_expr_error(p, condition);
+
+ struct mrb_ast_if_node *n = NEW_NODE(if, NODE_IF);
+ n->condition = condition;
+ n->then_body = then_body;
+ n->else_body = else_body;
+
+ return (node*)n;
+}
+
+/* struct: while_node(cond, body) */
+static node*
+new_while(parser_state *p, node *condition, node *body)
+{
+ void_expr_error(p, condition);
+
+ struct mrb_ast_while_node *n = NEW_NODE(while, NODE_WHILE);
+ n->condition = condition;
+ n->body = body;
+
+ return (node*)n;
+}
+
+/* struct: until_node(cond, body) */
+static node*
+new_until(parser_state *p, node *condition, node *body)
+{
+ void_expr_error(p, condition);
+
+ struct mrb_ast_until_node *n = NEW_NODE(until, NODE_UNTIL);
+ n->condition = condition;
+ n->body = body;
+
+ return (node*)n;
+}
+
+/* struct: while_node(cond, body) */
+static node*
+new_while_mod(parser_state *p, node *condition, node *body)
+{
+ node *while_node = new_while(p, condition, body);
+ struct mrb_ast_while_node *n = (struct mrb_ast_while_node*)while_node;
+ n->header.node_type = NODE_WHILE_MOD;
+ return while_node;
+}
+
+/* struct: until_node(cond, body) */
+static node*
+new_until_mod(parser_state *p, node *a, node *b)
+{
+ node *until_node = new_until(p, a, b);
+ struct mrb_ast_until_node *n = (struct mrb_ast_until_node*)until_node;
+ n->header.node_type = NODE_UNTIL_MOD;
+ return until_node;
+}
+
+
+/* struct: for_node(var, obj, body) */
+static node*
+new_for(parser_state *p, node *v, node *o, node *b)
+{
+ void_expr_error(p, o);
+
+ struct mrb_ast_for_node *n = NEW_NODE(for, NODE_FOR);
+ n->var = v;
+ n->iterable = o;
+ n->body = b;
+
+ return (node*)n;
+}
+
+/* struct: case_node(expr, when_clauses) - uses cons list */
+static node*
+new_case(parser_state *p, node *a, node *b)
+{
+ void_expr_error(p, a);
+
+ struct mrb_ast_case_node *n = NEW_NODE(case, NODE_CASE);
+ n->value = a;
+ n->body = b;
+
+ return (node*)n;
+}
+
+/* Pattern matching case/in expression */
+static node*
+new_case_match(parser_state *p, node *val, node *in_clauses)
+{
+ void_expr_error(p, val);
+
+ struct mrb_ast_case_match_node *n = NEW_NODE(case_match, NODE_CASE_MATCH);
+ n->value = val;
+ n->in_clauses = in_clauses;
+
+ return (node*)n;
+}
+
+/* Create value pattern node */
+static node*
+new_pat_value(parser_state *p, node *val)
+{
+ struct mrb_ast_pat_value_node *n = NEW_NODE(pat_value, NODE_PAT_VALUE);
+ n->value = val;
+ return (node*)n;
+}
+
+/* Create variable pattern node */
+static node*
+new_pat_var(parser_state *p, mrb_sym name)
+{
+ struct mrb_ast_pat_var_node *n = NEW_NODE(pat_var, NODE_PAT_VAR);
+ n->name = name;
+ /* Register as local variable if not wildcard */
+ if (name) {
+ local_add(p, name);
+ }
+ return (node*)n;
+}
+
+/* Create pin pattern node (^var) */
+static node*
+new_pat_pin(parser_state *p, mrb_sym name)
+{
+ struct mrb_ast_pat_pin_node *n = NEW_NODE(pat_pin, NODE_PAT_PIN);
+ n->name = name;
+ /* Pin operator references existing variable, does not create new binding */
+ return (node*)n;
+}
+
+/* Create as pattern node (pattern => var) */
+static node*
+new_pat_as(parser_state *p, node *pattern, mrb_sym name)
+{
+ struct mrb_ast_pat_as_node *n = NEW_NODE(pat_as, NODE_PAT_AS);
+ n->pattern = pattern;
+ n->name = name;
+ local_add(p, name);
+ return (node*)n;
+}
+
+/* Create alternative pattern node (pat1 | pat2) */
+static node*
+new_pat_alt(parser_state *p, node *left, node *right)
+{
+ struct mrb_ast_pat_alt_node *n = NEW_NODE(pat_alt, NODE_PAT_ALT);
+ n->left = left;
+ n->right = right;
+ return (node*)n;
+}
+
+/* Create array pattern node [a, b, *rest, c] */
+static node*
+new_pat_array(parser_state *p, node *pre, node *rest, node *post)
+{
+ struct mrb_ast_pat_array_node *n = NEW_NODE(pat_array, NODE_PAT_ARRAY);
+ n->pre = pre;
+ n->rest = rest;
+ n->post = post;
+ return (node*)n;
+}
+
+/* Create find pattern node [*pre, elems, *post] */
+static node*
+new_pat_find(parser_state *p, node *pre, node *elems, node *post)
+{
+ struct mrb_ast_pat_find_node *n = NEW_NODE(pat_find, NODE_PAT_FIND);
+ n->pre = pre;
+ n->elems = elems;
+ n->post = post;
+ return (node*)n;
+}
+
+/* Create hash pattern node {a:, b: x, **rest} */
+static node*
+new_pat_hash(parser_state *p, node *pairs, node *rest)
+{
+ struct mrb_ast_pat_hash_node *n = NEW_NODE(pat_hash, NODE_PAT_HASH);
+ n->pairs = pairs;
+ n->rest = rest;
+ return (node*)n;
+}
+
+/* Create one-line pattern matching node (expr in pattern / expr => pattern) */
+static node*
+new_match_pat(parser_state *p, node *value, node *pattern, mrb_bool raise_on_fail)
+{
+ struct mrb_ast_match_pat_node *n = NEW_NODE(match_pat, NODE_MATCH_PAT);
+ n->value = value;
+ n->pattern = pattern;
+ n->raise_on_fail = raise_on_fail;
+ return (node*)n;
+}
+
+/* Create in-clause node for case/in */
+static node*
+new_in(parser_state *p, node *pattern, node *guard, node *body, mrb_bool guard_is_unless)
+{
+ struct mrb_ast_in_node *n = NEW_NODE(in, NODE_IN);
+ n->pattern = pattern;
+ n->guard = guard;
+ n->body = body;
+ n->guard_is_unless = guard_is_unless;
+ return (node*)n;
+}
+
+/* struct: postexe_node(body) */
+static node*
+new_postexe(parser_state *p, node *a)
+{
+ struct mrb_ast_postexe_node *postexe_node = NEW_NODE(postexe, NODE_POSTEXE);
+ postexe_node->body = a;
+ return (node*)postexe_node;
+}
+
+/* struct: self_node() */
+static node*
+new_self(parser_state *p)
+{
+ struct mrb_ast_self_node *n = NEW_NODE(self, NODE_SELF);
+
+ return (node*)n;
+}
+
+/* struct: call_node(receiver, method, args) */
+static node*
+new_call(parser_state *p, node *receiver, mrb_sym method, node *args, int pass)
+{
+ /* Calculate size needed (fixed size now) */ struct mrb_ast_call_node *n = NEW_NODE(call, NODE_CALL);
+ n->receiver = receiver;
+ n->method_name = method;
+ n->safe_call = (pass == 0); /* pass == 0 means safe call (&.) */
+
+ /* Store args pointer directly - no need to unpack and repack */
+ n->args = args;
+
+ void_expr_error(p, receiver);
+ return (node*)n;
+}
+
+/* struct: fcall_node(method, args) */
+static node*
+new_fcall(parser_state *p, mrb_sym b, node *c)
+{
+ return new_call(p, NULL, b, c, '.');
+}
+
+/* (a b . c) */
+static node*
+new_callargs(parser_state *p, node *a, node *b, node *c)
+{
+ /* Allocate struct mrb_ast_callargs (fixed size, like new_args) */
+ struct mrb_ast_callargs *callargs = (struct mrb_ast_callargs*)parser_palloc(p, sizeof(struct mrb_ast_callargs));
+
+ /* Initialize members directly */
+ callargs->regular_args = a; /* Cons list of regular arguments (preserves splat compatibility) */
+ callargs->keyword_args = b; /* Keyword arguments hash node */
+ callargs->block_arg = c; /* Block argument node */
+
+ /* Return direct cast to node (like new_args) */
+ return (node*)callargs;
+}
+
+/* struct: super_node(args) */
+static node*
+new_super(parser_state *p, node *c)
+{
+ struct mrb_ast_super_node *n = NEW_NODE(super, NODE_SUPER);
+ n->args = c;
+
+ return (node*)n;
+}
+
+/* struct: zsuper_node() */
+static node*
+new_zsuper(parser_state *p)
+{
+ struct mrb_ast_super_node *n = NEW_NODE(super, NODE_ZSUPER);
+ n->args = NULL; /* zsuper initially has no args, but may be added by call_with_block */
+ return (node*)n;
+}
+
+/* struct: yield_node(args) */
+static node*
+new_yield(parser_state *p, node *c)
+{
+ /* Handle callargs structure - direct casting like new_args() */
+ if (c) {
+ struct mrb_ast_callargs *callargs = (struct mrb_ast_callargs*)c;
+ if (callargs->block_arg) {
+ yyerror(NULL, p, "both block arg and actual block given");
+ }
+ } struct mrb_ast_yield_node *n = NEW_NODE(yield, NODE_YIELD);
+ n->args = c;
+
+ return (node*)n;
+}
+
+/* struct: return_node(value) */
+static node*
+new_return(parser_state *p, node *c)
+{
+ struct mrb_ast_return_node *n = NEW_NODE(return, NODE_RETURN);
+ n->args = c;
+
+ return (node*)n;
+}
+
+/* struct: break_node(value) */
+static node*
+new_break(parser_state *p, node *c)
+{
+ struct mrb_ast_break_node *n = NEW_NODE(break, NODE_BREAK);
+ n->value = c;
+ return (node*)n;
+}
+
+/* struct: next_node(value) */
+static node*
+new_next(parser_state *p, node *c)
+{
+ struct mrb_ast_next_node *n = NEW_NODE(next, NODE_NEXT);
+ n->value = c;
+ return (node*)n;
+}
+
+/* struct: redo_node() */
+static node*
+new_redo(parser_state *p)
+{
+ struct mrb_ast_redo_node *n = NEW_NODE(redo, NODE_REDO);
+ return (node*)n;
+}
+
+/* struct: retry_node() */
+static node*
+new_retry(parser_state *p)
+{
+ struct mrb_ast_retry_node *n = NEW_NODE(retry, NODE_RETRY);
+ return (node*)n;
+}
+
+/* struct: dot2_node(beg, end) */
+static node*
+new_dot2(parser_state *p, node *a, node *b)
+{
+ struct mrb_ast_dot2_node *n = NEW_NODE(dot2, NODE_DOT2);
+ n->left = a;
+ n->right = b;
+
+ return (node*)n;
+}
+
+/* struct: dot3_node(beg, end) */
+static node*
+new_dot3(parser_state *p, node *a, node *b)
+{
+ struct mrb_ast_dot3_node *n = NEW_NODE(dot3, NODE_DOT3);
+ n->left = a;
+ n->right = b;
+
+ return (node*)n;
+}
+
+/* struct: colon2_node(base, name) */
+static node*
+new_colon2(parser_state *p, node *b, mrb_sym c)
+{
+ void_expr_error(p, b);
+
+ struct mrb_ast_colon2_node *colon2_node = NEW_NODE(colon2, NODE_COLON2);
+ colon2_node->base = b;
+ colon2_node->name = c;
+ return (node*)colon2_node;
+}
+
+/* struct: colon3_node(name) */
+static node*
+new_colon3(parser_state *p, mrb_sym c)
+{
+ struct mrb_ast_colon3_node *colon3_node = NEW_NODE(colon3, NODE_COLON3);
+ colon3_node->name = c;
+ return (node*)colon3_node;
+}
+
+/* struct: and_node(left, right) */
+static node*
+new_and(parser_state *p, node *a, node *b)
+{
+ void_expr_error(p, a);
+
+ struct mrb_ast_and_node *n = NEW_NODE(and, NODE_AND);
+ n->left = a;
+ n->right = b;
+
+ return (node*)n;
+}
+
+/* struct: or_node(left, right) */
+static node*
+new_or(parser_state *p, node *a, node *b)
+{
+ void_expr_error(p, a);
+
+ struct mrb_ast_or_node *n = NEW_NODE(or, NODE_OR);
+ n->left = a;
+ n->right = b;
+
+ return (node*)n;
+}
+
+/* struct: array_node(elements) - uses cons list */
+static node*
+new_array(parser_state *p, node *a)
+{
+ struct mrb_ast_array_node *n = NEW_NODE(array, NODE_ARRAY);
+ n->elements = a;
+
+ return (node*)n;
+}
+
+/* struct: splat_node(value) */
+static node*
+new_splat(parser_state *p, node *a)
+{
+ void_expr_error(p, a);
+
+ struct mrb_ast_splat_node *splat_node = NEW_NODE(splat, NODE_SPLAT);
+ splat_node->value = a;
+ return (node*)splat_node;
+}
+
+/* struct: hash_node(pairs) - uses cons list */
+static node*
+new_hash(parser_state *p, node *a)
+{
+ struct mrb_ast_hash_node *n = NEW_NODE(hash, NODE_HASH);
+ n->pairs = a;
+
+ return (node*)n;
+}
+
+/* (:sym . a) */
+/* Symbol node creation - supports both variable and legacy modes */
+static node*
+new_sym(parser_state *p, mrb_sym sym)
+{
+ struct mrb_ast_sym_node *n = NEW_NODE(sym, NODE_SYM);
+ n->symbol = sym;
+
+ return (node*)n;
+}
+
+static node*
+new_xvar(parser_state *p, mrb_sym sym, enum node_type type)
+{
+ struct mrb_ast_var_node *n = NEW_NODE(var, type);
+ n->symbol = sym;
+
+ return (node*)n;
+}
+
+#define new_lvar(p, sym) new_xvar(p, sym, NODE_LVAR)
+#define new_ivar(p, sym) new_xvar(p, sym, NODE_IVAR)
+#define new_gvar(p, sym) new_xvar(p, sym, NODE_GVAR)
+#define new_cvar(p, sym) new_xvar(p, sym, NODE_CVAR)
+
+static mrb_sym
+new_strsym(parser_state *p, node* str)
+{
+ size_t len = (size_t)str->car;
+ const char *s = (const char*)str->cdr;
+
+ return mrb_intern(p->mrb, s, len);
+}
+
+/* (:nvar . a) */
+static node*
+new_nvar(parser_state *p, int num)
+{
+ int nvar;
+ node *nvars = p->nvars->cdr;
+ while (nvars) {
+ nvar = node_to_int(nvars->car);
+ if (nvar == -2) break; /* top of the scope */
+ if (nvar > 0) {
+ yyerror(NULL, p, "numbered parameter used in outer block");
+ break;
+ }
+ nvars->car = int_to_node(-1);
+ nvars = nvars->cdr;
+ }
+ nvar = node_to_int(p->nvars->car);
+ if (nvar == -1) {
+ yyerror(NULL, p, "numbered parameter used in inner block");
+ }
+ else {
+ p->nvars->car = int_to_node(nvar > num ? nvar : num);
+ }
+ struct mrb_ast_nvar_node *n = NEW_NODE(nvar, NODE_NVAR);
+ n->num = num;
+ return (node*)n;
+}
+
+/* struct: const_node(name) */
+static node*
+new_const(parser_state *p, mrb_sym sym)
+{
+ struct mrb_ast_const_node *n = NEW_NODE(const, NODE_CONST);
+ n->symbol = sym;
+
+ return (node*)n;
+}
+
+/* struct: undef_node(syms) - uses cons list */
+static node*
+new_undef(parser_state *p, node *syms)
+{
+ struct mrb_ast_undef_node *undef_node = NEW_NODE(undef, NODE_UNDEF);
+ undef_node->syms = syms;
+ return (node*)undef_node;
+}
+
+/* struct: class_node(path, super, body) */
+static node*
+new_class(parser_state *p, node *c, node *s, node *b)
+{
+ void_expr_error(p, s);
+
+ struct mrb_ast_class_node *n = NEW_NODE(class, NODE_CLASS);
+ n->name = c;
+ n->superclass = s;
+ n->body = cons(locals_node(p), b);
+
+ return (node*)n;
+}
+
+/* struct: sclass_node(obj, body) */
+static node*
+new_sclass(parser_state *p, node *o, node *b)
+{
+ void_expr_error(p, o);
+
+ struct mrb_ast_sclass_node *n = NEW_NODE(sclass, NODE_SCLASS);
+ n->obj = o;
+ n->body = cons(locals_node(p), b);
+
+ return (node*)n;
+}
+
+/* struct: module_node(path, body) */
+static node*
+new_module(parser_state *p, node *m, node *b)
+{
+ struct mrb_ast_module_node *n = NEW_NODE(module, NODE_MODULE);
+ n->name = m;
+ n->body = cons(locals_node(p), b);
+
+ return (node*)n;
+}
+
+/* struct: def_node(name, args, body) */
+static node*
+new_def(parser_state *p, mrb_sym name)
+{
+ struct mrb_ast_def_node *n = NEW_NODE(def, NODE_DEF);
+ n->name = name;
+ n->args = (struct mrb_ast_args *)int_to_node(p->cmdarg_stack);
+ n->locals = local_switch(p);
+ n->body = NULL;
+
+ return (node*)n;
+}
+
+static void
+defn_setup(parser_state *p, node *d, node *a, node *b)
+{
+ struct mrb_ast_def_node *n = def_node(d);
+ node *locals = n->locals;
+
+ n->locals = locals_node(p);
+ p->cmdarg_stack = node_to_int(n->args);
+ n->args = (struct mrb_ast_args *)a;
+ n->body = b;
+ local_resume(p, locals);
+}
+
+/* struct: sdef_node(obj, name, args, body) */
+static node*
+new_sdef(parser_state *p, node *o, mrb_sym name)
+{
+ void_expr_error(p, o);
+
+ struct mrb_ast_sdef_node *sdef_node = NEW_NODE(sdef, NODE_SDEF);
+ sdef_node->obj = o;
+ sdef_node->name = name;
+ sdef_node->args = (struct mrb_ast_args *)int_to_node(p->cmdarg_stack);
+ sdef_node->locals = local_switch(p);
+ sdef_node->body = NULL;
+ return (node*)sdef_node;
+}
+
+static void
+local_add_margs(parser_state *p, node *n)
+{
+ while (n) {
+ if (node_type(n->car) == NODE_MARG) {
+ struct mrb_ast_masgn_node *masgn_n = (struct mrb_ast_masgn_node*)n->car;
+ node *rhs = masgn_n->rhs;
+
+ /* For parameter destructuring, rhs contains the locals */
+ if (rhs) {
+ node *t = rhs;
+ while (t) {
+ local_add_f(p, node_to_sym(t->car));
+ t = t->cdr;
+ }
+ /* Clear cons list RHS immediately after use */
+ masgn_n->rhs = NULL;
+ }
+
+ /* Process nested destructuring in lhs components */
+ if (masgn_n->pre) {
+ local_add_margs(p, masgn_n->pre);
+ }
+ if (masgn_n->post) {
+ local_add_margs(p, masgn_n->post);
+ }
+ }
+ n = n->cdr;
+ }
+}
+
+
+static void
+local_add_lv(parser_state *p, node *lv)
+{
+ while (lv) {
+ local_add_f(p, node_to_sym(lv->car));
+ lv = lv->cdr;
+ }
+}
+
+/* (m o r m2 tail) */
+/* m: (a b c) */
+/* o: ((a . e1) (b . e2)) */
+/* r: a */
+/* m2: (a b c) */
+/* b: a */
+static node*
+new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, node *tail)
+{
+ local_add_margs(p, m);
+ local_add_margs(p, m2);
+
+ /* Save original optional arguments before processing */
+ node *orig_opt = opt;
+
+ /* Process optional arguments (keep original side effects) */
+ while (opt) {
+ /* opt: (sym . (opt . lv)) -> (sym . opt) */
+ local_add_lv(p, opt->car->cdr->cdr);
+ opt->car->cdr = opt->car->cdr->car;
+ opt = opt->cdr;
+ }
+
+ /* Allocate struct mrb_ast_args (no hdr) */
+ struct mrb_ast_args *args = (struct mrb_ast_args*)parser_palloc(p, sizeof(struct mrb_ast_args));
+
+ /* Initialize members */
+ args->mandatory_args = m;
+ args->optional_args = orig_opt;
+ args->rest_arg = rest;
+ args->post_mandatory_args = m2;
+
+ /* Deconstruct tail cons list: (kws . (kwrest . blk)) */
+ if (tail) {
+ args->keyword_args = (node*)tail->car; /* kws */
+ args->kwrest_arg = (mrb_sym)(intptr_t)tail->cdr->car; /* kwrest */
+ args->block_arg = (mrb_sym)(intptr_t)tail->cdr->cdr; /* blk */
+ cons_free(tail->cdr);
+ cons_free(tail);
+ }
+ else {
+ args->keyword_args = NULL;
+ args->kwrest_arg = 0;
+ args->block_arg = 0;
+ }
+
+ return (node*)args;
+}
+
+/* struct: args_tail_node(kwargs, kwrest, block) */
+static node*
+new_args_tail(parser_state *p, node *kws, mrb_sym kwrest, mrb_sym blk)
+{
+ node *k;
+
+ if (kws || kwrest) {
+ local_add_kw(p, kwrest);
+ }
+
+ local_add_blk(p);
+ if (blk && blk != MRB_SYM(nil)) local_add_f(p, blk);
+
+ /* allocate register for keywords arguments */
+ /* order is for Proc#parameters */
+ for (k = kws; k; k = k->cdr) {
+ if (!k->car->cdr) { /* allocate required keywords - simplified structure: (key . NULL) */
+ local_add_f(p, node_to_sym(k->car->car));
+ }
+ }
+ for (k = kws; k; k = k->cdr) {
+ if (k->car->cdr) { /* allocate keywords with default - simplified structure: (key . value) */
+ local_add_lv(p, k->car->cdr->cdr); /* value->cdr for default args */
+ k->car->cdr = k->car->cdr->car; /* value->car for default args */
+ local_add_f(p, node_to_sym(k->car->car));
+ }
+ }
+
+ /* Return cons list: (keyword . (kwrest . blk)) */
+ return cons(kws, cons(sym_to_node(kwrest), sym_to_node(blk)));
+}
+
+/* (kw_sym . def_arg) - simplified from NODE_KW_ARG wrapper */
+static node*
+new_kw_arg(parser_state *p, mrb_sym kw, node *def_arg)
+{
+ mrb_assert(kw);
+ return cons(sym_to_node(kw), def_arg);
+}
+
+/* (:kw_rest_args . a) */
+static node*
+new_kw_rest_args(parser_state *p, mrb_sym sym)
+{
+ return sym_to_node(intern_op(pow)); /* Use ** symbol as direct marker */
+}
+
+static node*
+new_args_dots(parser_state *p, node *m)
+{
+ mrb_sym r = intern_op(mul);
+ mrb_sym k = intern_op(pow);
+ mrb_sym b = intern_op(and);
+ local_add_f(p, r);
+ return new_args(p, m, 0, r, 0, new_args_tail(p, NULL, k, b));
+}
+
+/* struct: block_arg_node(value) */
+static node*
+new_block_arg(parser_state *p, node *a)
+{
+ struct mrb_ast_block_arg_node *block_arg_node = NEW_NODE(block_arg, NODE_BLOCK_ARG);
+ block_arg_node->value = a;
+ return (node*)block_arg_node;
+}
+
+static node*
+setup_numparams(parser_state *p, node *a)
+{
+ int nvars = node_to_int(p->nvars->car);
+ if (nvars > 0) {
+ int i;
+ mrb_sym sym;
+ // Check if any arguments are already defined
+ struct mrb_ast_args *args = (struct mrb_ast_args *)a;
+ if (a && (args->mandatory_args || args->optional_args || args->rest_arg ||
+ args->post_mandatory_args || args->keyword_args || args->kwrest_arg)) {
+ yyerror(NULL, p, "ordinary parameter is defined");
+ }
+ else if (p->locals) {
+ /* p->locals should not be NULL unless error happens before the point */
+ node* args = 0;
+ for (i = nvars; i > 0; i--) {
+ char buf[3];
+
+ buf[0] = '_';
+ buf[1] = i+'0';
+ buf[2] = '\0';
+ sym = intern_cstr(buf);
+ args = cons(new_lvar(p, sym), args);
+ p->locals->car = cons(sym_to_node(sym), p->locals->car);
+ }
+ a = new_args(p, args, 0, 0, 0, 0);
+ }
+ }
+ return a;
+}
+
+/* struct: block_node(args, body) */
+static node*
+new_block(parser_state *p, node *a, node *b)
+{
+ a = setup_numparams(p, a); struct mrb_ast_block_node *n = NEW_NODE(block, NODE_BLOCK);
+ n->locals = locals_node(p);
+ n->args = (struct mrb_ast_args *)a;
+ n->body = b;
+
+ return (node*)n;
+}
+
+/* struct: lambda_node(args, body) */
+static node*
+new_lambda(parser_state *p, node *a, node *b)
+{
+ a = setup_numparams(p, a); struct mrb_ast_lambda_node *lambda_node = NEW_NODE(lambda, NODE_LAMBDA);
+ lambda_node->locals = locals_node(p);
+ lambda_node->args = (struct mrb_ast_args *)a;
+ lambda_node->body = b;
+ return (node*)lambda_node;
+}
+
+/* struct: asgn_node(lhs, rhs) */
+static node*
+new_asgn(parser_state *p, node *a, node *b)
+{
+ void_expr_error(p, b);
+
+ struct mrb_ast_asgn_node *n = NEW_NODE(asgn, NODE_ASGN);
+ n->lhs = a;
+ n->rhs = b;
+
+ return (node*)n;
+}
+
+/* Helper function to create MASGN/MARG nodes */
+static node*
+new_masgn_helper(parser_state *p, node *a, node *b, enum node_type node_type)
+{
+ struct mrb_ast_masgn_node *n = NEW_NODE(masgn, node_type);
+
+ /* Extract pre, rest, post from cons list structure (a b c) */
+ if (a) {
+ n->pre = a->car; /* Pre-splat variables */
+ if (a->cdr) {
+ n->rest = a->cdr->car; /* Splat variable (or -1 for anonymous) */
+ if (a->cdr->cdr) {
+ n->post = a->cdr->cdr->car; /* Post-splat variables */
+ cons_free(a->cdr->cdr);
+ }
+ else {
+ n->post = NULL;
+ }
+ cons_free(a->cdr);
+ }
+ else {
+ n->rest = NULL;
+ n->post = NULL;
+ }
+ cons_free(a);
+ }
+ else {
+ n->pre = NULL;
+ n->rest = NULL;
+ n->post = NULL;
+ }
+ n->rhs = b;
+
+ return (node*)n;
+}
+
+/* struct: masgn_node(lhs, rhs) */
+static node*
+new_masgn(parser_state *p, node *a, node *b)
+{
+ void_expr_error(p, b);
+ return new_masgn_helper(p, a, b, NODE_MASGN);
+}
+
+/* (:marg mlhs mrhs) no check - for parameter destructuring */
+static node*
+new_marg(parser_state *p, node *a)
+{
+ return new_masgn_helper(p, a, p->locals->car, NODE_MARG);
+}
+
+/* struct: op_asgn_node(lhs, op, rhs) */
+static node*
+new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b)
+{
+ void_expr_error(p, b);
+
+ struct mrb_ast_op_asgn_node *n = NEW_NODE(op_asgn, NODE_OP_ASGN);
+ n->lhs = a;
+ n->op = op;
+ n->rhs = b;
+ return (node*)n;
+}
+
+static node*
+new_int_n(parser_state *p, int32_t val)
+{
+ struct mrb_ast_int_node *n = NEW_NODE(int, NODE_INT);
+ n->value = val;
+
+ return (node*)n;
+}
+
+static node*
+new_imaginary(parser_state *p, node *imaginary)
+{
+ return new_fcall(p, MRB_SYM(Complex),
+ new_callargs(p, list2(new_int_n(p, 0), imaginary), 0, 0));
+}
+
+static node*
+new_rational(parser_state *p, node *rational)
+{
+ return new_fcall(p, MRB_SYM(Rational), new_callargs(p, list1(rational), 0, 0));
+}
+
+/* Read integer into int32_t with overflow detection */
+static mrb_bool
+read_int32(const char *p, int base, int32_t *result)
+{
+ const char *e = p + strlen(p);
+ int32_t value = 0;
+ mrb_bool neg = FALSE;
+
+ if (base < 2 || base > 16) {
+ return FALSE;
+ }
+
+ if (*p == '+') {
+ p++;
+ }
+ else if (*p == '-') {
+ neg = TRUE;
+ p++;
+ }
+
+ while (p < e) {
+ int n;
+ char c = *p;
+
+ /* Skip underscores */
+ if (c == '_') {
+ p++;
+ continue;
+ }
+
+ /* Parse digit */
+ if (c >= '0' && c <= '9') {
+ n = c - '0';
+ }
+ else if (c >= 'a' && c <= 'f') {
+ n = c - 'a' + 10;
+ }
+ else if (c >= 'A' && c <= 'F') {
+ n = c - 'A' + 10;
+ }
+ else {
+ /* Invalid character */
+ return FALSE;
+ }
+
+ if (n >= base) {
+ /* Digit not valid for this base */
+ return FALSE;
+ }
+
+ /* Check for multiplication overflow */
+ if (value > INT32_MAX / base) {
+ return FALSE;
+ }
+
+ value *= base;
+
+ /* Check for addition overflow */
+ if (value > INT32_MAX - n) {
+ /* Special case: -INT32_MIN is valid */
+ if (neg && value == (INT32_MAX - n + 1) && p + 1 == e) {
+ *result = INT32_MIN;
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ value += n;
+ p++;
+ }
+
+ *result = neg ? -value : value;
+ return TRUE;
+}
+
+static node*
+new_int(parser_state *p, const char *s, int base, int suffix)
+{
+ int32_t val;
+ node* result;
+
+ /* Try to parse as int32_t first */
+ if (read_int32(s, base, &val)) {
+ result = new_int_n(p, val);
+ }
+ else {
+ /* Big integer - create NODE_BIGINT */
+ struct mrb_ast_bigint_node *n = NEW_NODE(bigint, NODE_BIGINT);
+ n->string = strdup(s);
+ n->base = base;
+
+ result = (node*)n;
+ }
+
+ /* Handle suffix modifiers */
+ if (suffix & NUM_SUFFIX_R) {
+ result = new_rational(p, result);
+ }
+ if (suffix & NUM_SUFFIX_I) {
+ result = new_imaginary(p, result);
+ }
+
+ return result;
+}
+
+#ifndef MRB_NO_FLOAT
+/* struct: float_node(value) */
+static node*
+new_float(parser_state *p, const char *s, int suffix)
+{
+ struct mrb_ast_float_node *n = NEW_NODE(float, NODE_FLOAT);
+ n->value = strdup(s);
+
+ node* result = (node*)n;
+
+ if (suffix & NUM_SUFFIX_R) {
+ result = new_rational(p, result);
+ }
+ if (suffix & NUM_SUFFIX_I) {
+ result = new_imaginary(p, result);
+ }
+ return result;
+}
+#endif
+
+/* Create string node from cons list */
+/* struct: str_node(str) */
+static node*
+new_str(parser_state *p, node *a)
+{
+ struct mrb_ast_str_node *n = NEW_NODE(str, NODE_STR);
+ n->list = a;
+
+ return (node*)n;
+}
+
+/* struct: xstr_node(str) */
+static node*
+new_xstr(parser_state *p, node *a)
+{
+ struct mrb_ast_xstr_node *n = NEW_NODE(xstr, NODE_XSTR);
+ n->list = a;
+ return (node*)n;
+}
+
+/* struct: dsym_node(parts) - uses cons list */
+static node*
+new_dsym(parser_state *p, node *a)
+{
+ struct mrb_ast_str_node *n = NEW_NODE(str, NODE_DSYM);
+ n->list = a;
+ return (node*)n;
+}
+
+/* struct: regx_node(pattern, flags, encoding) */
+static node*
+new_regx(parser_state *p, node *list, const char *flags, const char *encoding)
+{
+ struct mrb_ast_regx_node *n = NEW_NODE(regx, NODE_REGX);
+ n->list = list;
+ n->flags = flags;
+ n->encoding = encoding;
+ return (node*)n;
+}
+
+/* struct: back_ref_node(n) */
+static node*
+new_back_ref(parser_state *p, int n)
+{
+ struct mrb_ast_back_ref_node *backref_node = NEW_NODE(back_ref, NODE_BACK_REF);
+ backref_node->type = n;
+ return (node*)backref_node;
+}
+
+/* struct: nth_ref_node(n) */
+static node*
+new_nth_ref(parser_state *p, int n)
+{
+ struct mrb_ast_nth_ref_node *nthref_node = NEW_NODE(nth_ref, NODE_NTH_REF);
+ nthref_node->nth = n;
+ return (node*)nthref_node;
+}
+
+/* struct: heredoc_node(str) */
+static node*
+new_heredoc(parser_state *p, struct mrb_parser_heredoc_info **infop)
+{
+ struct mrb_ast_heredoc_node *n = NEW_NODE(heredoc, NODE_HEREDOC);
+
+ /* Initialize embedded heredoc info struct */
+ n->info.allow_indent = FALSE;
+ n->info.remove_indent = FALSE;
+ n->info.line_head = FALSE;
+ n->info.indent = 0;
+ n->info.indented = NULL;
+ n->info.type = str_not_parsing; // Will be set by heredoc processing
+ n->info.term = NULL; // Will be set by heredoc processing
+ n->info.term_len = 0;
+ n->info.doc = NULL;
+
+ /* Return pointer to embedded info if requested */
+ *infop = &n->info;
+
+ return (node*)n;
+}
+
+static void
+new_bv(parser_state *p, mrb_sym id)
+{
+}
+
+static node*
+new_literal_delim(parser_state *p)
+{
+ return cons((node*)0, (node*)0);
+}
+
+/* Helper for creating string representation cons (length . string_ptr) */
+static node*
+new_str_rep(parser_state *p, const char *str, int len)
+{
+ return cons(int_to_node(len), (node*)strndup(str, len));
+}
+
+/* Helper for creating string representation from current token */
+static node*
+new_str_tok(parser_state *p)
+{
+ return new_str_rep(p, tok(p), toklen(p));
+}
+
+/* Helper for creating empty string representation */
+static node*
+new_str_empty(parser_state *p)
+{
+ return new_str_rep(p, "", 0);
+}
+
+/* (:words . a) */
+static node*
+new_words(parser_state *p, node *a)
+{
+ struct mrb_ast_words_node *words_node = NEW_NODE(words, NODE_WORDS);
+ words_node->args = a;
+ return (node*)words_node;
+}
+
+/* (:symbols . a) */
+static node*
+new_symbols(parser_state *p, node *a)
+{
+ struct mrb_ast_symbols_node *symbols_node = NEW_NODE(symbols, NODE_SYMBOLS);
+ symbols_node->args = a;
+ return (node*)symbols_node;
+}
+
+/* xxx ----------------------------- */
+
+/* (:call a op) */
+static node*
+call_uni_op(parser_state *p, node *recv, const char *m)
+{
+ void_expr_error(p, recv);
+ return new_call(p, recv, intern_cstr(m), 0, '.');
+}
+
+/* (:call a op b) */
+static node*
+call_bin_op(parser_state *p, node *recv, const char *m, node *arg1)
+{
+ return new_call(p, recv, intern_cstr(m), new_callargs(p, list1(arg1), 0, 0), '.');
+}
+
+static void
+args_with_block(parser_state *p, node *a, node *b)
+{
+ if (b) {
+ /* Handle callargs structure - direct casting like new_args() */
+ struct mrb_ast_callargs *callargs = (struct mrb_ast_callargs*)a;
+ if (callargs->block_arg) {
+ yyerror(NULL, p, "both block arg and actual block given");
+ }
+ callargs->block_arg = b;
+ }
+}
+
+static void
+endless_method_name(parser_state *p, node *defn)
+{
+ struct mrb_ast_def_node *def = (struct mrb_ast_def_node*)defn;
+ mrb_sym sym = def->name;
+ mrb_int len;
+ const char *name = mrb_sym_name_len(p->mrb, sym, &len);
+
+ if (len > 1 && name[len-1] == '=') {
+ for (int i=0; i<len-1; i++) {
+ if (!identchar(name[i])) return;
+ }
+ yyerror(NULL, p, "setter method cannot be defined by endless method definition");
+ }
+}
+
+static void
+call_with_block(parser_state *p, node *a, node *b)
+{
+ if (!a) return;
+
+ /* Handle direct variable-sized nodes */
+ struct mrb_ast_var_header *header = (struct mrb_ast_var_header*)a;
+
+ enum node_type var_type = (enum node_type)header->node_type;
+ switch (var_type) {
+ case NODE_SUPER:
+ case NODE_ZSUPER:
+ /* For variable-sized super/zsuper nodes, update the args field directly */
+ {
+ struct mrb_ast_super_node *super_n = super_node(a);
+ if (!super_n->args) {
+ super_n->args = new_callargs(p, 0, 0, b);
+ }
+ else {
+ args_with_block(p, super_n->args, b);
+ }
+ }
+ break;
+ case NODE_YIELD:
+ /* Variable-sized yield nodes should generate an error when given a block */
+ yyerror(NULL, p, "block given to yield");
+ break;
+ case NODE_RETURN:
+ /* Variable-sized return nodes - recursively call with args */
+ {
+ struct mrb_ast_return_node *return_n = return_node(a);
+ if (return_n->args != NULL) {
+ call_with_block(p, return_n->args, b);
+ }
+ }
+ break;
+ case NODE_BREAK:
+ /* Variable-sized break nodes - recursively call with value */
+ {
+ struct mrb_ast_break_node *break_n = (struct mrb_ast_break_node*)a;
+ if (break_n->value != NULL) {
+ call_with_block(p, break_n->value, b);
+ }
+ }
+ break;
+ case NODE_NEXT:
+ /* Variable-sized next nodes - recursively call with value */
+ {
+ struct mrb_ast_next_node *next_n = (struct mrb_ast_next_node*)a;
+ if (next_n->value != NULL) {
+ call_with_block(p, next_n->value, b);
+ }
+ }
+ break;
+ case NODE_CALL:
+ /* Variable-sized call nodes - add block to existing args */
+ {
+ struct mrb_ast_call_node *call = call_node(a);
+
+ if (call->args && callargs_node(call->args)->block_arg) {
+ yyerror(NULL, p, "both block arg and actual block given");
+ return;
+ }
+
+ /* Use existing args and add block */
+ if (call->args) {
+ /* Modify existing callargs structure to add block */
+ args_with_block(p, call->args, b);
+ }
+ else {
+ /* Create new callargs with just the block */
+ call->args = new_callargs(p, NULL, NULL, b);
+ }
+ }
+ break;
+ default:
+ /* For other variable-sized nodes, do nothing */
+ break;
+ }
+}
+
+static node*
+new_negate(parser_state *p, node *n)
+{
+ struct mrb_ast_negate_node *negate_node = NEW_NODE(negate, NODE_NEGATE);
+ negate_node->operand = n;
+ return (node*)negate_node;
+}
+
+static node*
+cond(node *n)
+{
+ return n;
+}
+
+static node*
+ret_args(parser_state *p, node *n)
+{
+ /* Handle callargs structure - direct casting like new_args() */
+ struct mrb_ast_callargs *callargs = (struct mrb_ast_callargs*)n;
+ if (callargs->block_arg) {
+ yyerror(NULL, p, "block argument should not be given");
+ return NULL;
+ }
+ if (!callargs->regular_args) return NULL;
+ if (!callargs->regular_args->cdr) return callargs->regular_args->car;
+ return new_array(p, callargs->regular_args);
+}
+
+static void
+assignable(parser_state *p, node *lhs)
+{
+ switch (node_type(lhs)) {
+ case NODE_LVAR:
+ local_add(p, var_node(lhs)->symbol);
+ break;
+ case NODE_CONST:
+ if (p->in_def)
+ yyerror(NULL, p, "dynamic constant assignment");
+ break;
+ default:
+ /* Other node types don't need special handling in assignable */
+ break;
+ }
+}
+
+static node*
+var_reference(parser_state *p, node *lhs)
+{
+ /* Check if this is a variable-sized node */
+ if (node_type_p(lhs, NODE_LVAR)) {
+ mrb_sym sym = var_node(lhs)->symbol;
+ if (!local_var_p(p, sym)) {
+ node *n = new_fcall(p, sym, 0);
+ /* Don't free variable-sized nodes - they're managed by the parser allocator */
+ return n;
+ }
+ }
+ return lhs;
+}
+
+static node*
+label_reference(parser_state *p, mrb_sym sym)
+{
+ const char *name = mrb_sym_name(p->mrb, sym);
+
+ if (local_var_p(p, sym)) {
+ return new_lvar(p, sym);
+ }
+ else if (ISUPPER(name[0])) {
+ return new_const(p, sym);
+ }
+ else {
+ return new_fcall(p, sym, 0);
+ }
+}
+
+typedef enum mrb_string_type string_type;
+
+typedef struct parser_lex_strterm {
+ int type;
+ int level;
+ int term;
+ int paren;
+ struct parser_lex_strterm *prev;
+} parser_lex_strterm;
+
+static parser_lex_strterm*
+new_strterm(parser_state *p, string_type type, int term, int paren)
+{
+ parser_lex_strterm *lex = (parser_lex_strterm*)parser_palloc(p, sizeof(parser_lex_strterm));
+ lex->type = type;
+ lex->level = 0;
+ lex->term = term;
+ lex->paren = paren;
+ lex->prev = p->lex_strterm;
+ return lex;
+}
+
+static void
+end_strterm(parser_state *p)
+{
+ parser_lex_strterm *term = p->lex_strterm->prev;
+ parser_pfree(p->lex_strterm);
+ p->lex_strterm = term;
+}
+
+static node*
+push_strterm(parser_state *p)
+{
+ node *n = cons((node*)p->lex_strterm, p->parsing_heredoc);
+ p->lex_strterm = NULL;
+ return n;
+}
+
+static void
+pop_strterm(parser_state *p, node *n)
+{
+ p->lex_strterm = (parser_lex_strterm*)n->car;
+ p->parsing_heredoc = n->cdr;
+ cons_free(n);
+}
+
+static parser_heredoc_info *
+parsing_heredoc_info(parser_state *p)
+{
+ node *nd = p->parsing_heredoc;
+ if (nd == NULL) return NULL;
+ /* mrb_assert(nd->car->car == NODE_HEREDOC); */
+ if (node_type(nd->car) == NODE_HEREDOC) {
+ /* Variable-sized heredoc node - return address of embedded info struct */
+ struct mrb_ast_heredoc_node *heredoc = (struct mrb_ast_heredoc_node*)nd->car;
+ return &heredoc->info;
+ }
+ return (parser_heredoc_info*)nd->car->cdr;
+}
+
+static void
+heredoc_treat_nextline(parser_state *p)
+{
+ if (p->heredocs_from_nextline == NULL) return;
+ if (p->parsing_heredoc && p->lex_strterm) {
+ append(p->heredocs_from_nextline, p->parsing_heredoc);
+ }
+ p->parsing_heredoc = p->heredocs_from_nextline;
+ p->lex_strterm = new_strterm(p, parsing_heredoc_info(p)->type, 0, 0);
+ p->heredocs_from_nextline = NULL;
+}
+
+static void
+heredoc_end(parser_state *p)
+{
+ p->parsing_heredoc = p->parsing_heredoc->cdr;
+ if (p->parsing_heredoc == NULL) {
+ p->lstate = EXPR_BEG;
+ end_strterm(p);
+ }
+ else {
+ /* next heredoc */
+ p->lex_strterm->type = parsing_heredoc_info(p)->type;
+ }
+}
+#define is_strterm_type(p,str_func) ((p)->lex_strterm->type & (str_func))
+
+static void
+prohibit_literals(parser_state *p, node *n)
+{
+ if (n == 0) {
+ yyerror(NULL, p, "can't define singleton method for ().");
+ }
+ else {
+ enum node_type nt = node_type(n);
+ switch (nt) {
+ case NODE_INT:
+ case NODE_STR:
+ case NODE_XSTR:
+ case NODE_REGX:
+ case NODE_FLOAT:
+ case NODE_ARRAY:
+ case NODE_HEREDOC:
+ yyerror(NULL, p, "can't define singleton method for literals");
+ default:
+ break;
+ }
+ }
+}
+
+/* xxx ----------------------------- */
+
+
+#line 2061 "mrbgems/mruby-compiler/core/y.tab.c"
+
+# ifndef YY_CAST
+# ifdef __cplusplus
+# define YY_CAST(Type, Val) static_cast<Type> (Val)
+# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+# else
+# define YY_CAST(Type, Val) ((Type) (Val))
+# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+# endif
+# endif
+# ifndef YY_NULLPTR
+# if defined __cplusplus
+# if 201103L <= __cplusplus
+# define YY_NULLPTR nullptr
+# else
+# define YY_NULLPTR 0
+# endif
+# else
+# define YY_NULLPTR ((void*)0)
+# endif
+# endif
+
+/* Use api.header.include to #include this header
+ instead of duplicating it here. */
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG && !defined(yydebug)
+extern int yydebug;
+#endif
+
+
+/* Token kinds. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ YYEMPTY = -2,
+ YYEOF = 0, /* "end of file" */
+ YYerror = 256, /* error */
+ YYUNDEF = 257, /* "invalid token" */
+ keyword_class = 258, /* "'class'" */
+ keyword_module = 259, /* "'module'" */
+ keyword_def = 260, /* "'def'" */
+ keyword_begin = 261, /* "'begin'" */
+ keyword_if = 262, /* "'if'" */
+ keyword_unless = 263, /* "'unless'" */
+ keyword_while = 264, /* "'while'" */
+ keyword_until = 265, /* "'until'" */
+ keyword_for = 266, /* "'for'" */
+ keyword_undef = 267, /* "'undef'" */
+ keyword_rescue = 268, /* "'rescue'" */
+ keyword_ensure = 269, /* "'ensure'" */
+ keyword_end = 270, /* "'end'" */
+ keyword_then = 271, /* "'then'" */
+ keyword_elsif = 272, /* "'elsif'" */
+ keyword_else = 273, /* "'else'" */
+ keyword_case = 274, /* "'case'" */
+ keyword_when = 275, /* "'when'" */
+ keyword_break = 276, /* "'break'" */
+ keyword_next = 277, /* "'next'" */
+ keyword_redo = 278, /* "'redo'" */
+ keyword_retry = 279, /* "'retry'" */
+ keyword_in = 280, /* "'in'" */
+ keyword_do = 281, /* "'do'" */
+ keyword_do_cond = 282, /* "'do' for condition" */
+ keyword_do_block = 283, /* "'do' for block" */
+ keyword_do_LAMBDA = 284, /* "'do' for lambda" */
+ keyword_return = 285, /* "'return'" */
+ keyword_yield = 286, /* "'yield'" */
+ keyword_super = 287, /* "'super'" */
+ keyword_self = 288, /* "'self'" */
+ keyword_nil = 289, /* "'nil'" */
+ keyword_true = 290, /* "'true'" */
+ keyword_false = 291, /* "'false'" */
+ keyword_and = 292, /* "'and'" */
+ keyword_or = 293, /* "'or'" */
+ keyword_not = 294, /* "'not'" */
+ modifier_if = 295, /* "'if' modifier" */
+ modifier_unless = 296, /* "'unless' modifier" */
+ modifier_while = 297, /* "'while' modifier" */
+ modifier_until = 298, /* "'until' modifier" */
+ modifier_rescue = 299, /* "'rescue' modifier" */
+ keyword_alias = 300, /* "'alias'" */
+ keyword_BEGIN = 301, /* "'BEGIN'" */
+ keyword_END = 302, /* "'END'" */
+ keyword__LINE__ = 303, /* "'__LINE__'" */
+ keyword__FILE__ = 304, /* "'__FILE__'" */
+ keyword__ENCODING__ = 305, /* "'__ENCODING__'" */
+ tIDENTIFIER = 306, /* "local variable or method" */
+ tFID = 307, /* "method" */
+ tGVAR = 308, /* "global variable" */
+ tIVAR = 309, /* "instance variable" */
+ tCONSTANT = 310, /* "constant" */
+ tCVAR = 311, /* "class variable" */
+ tLABEL_TAG = 312, /* "label" */
+ tINTEGER = 313, /* "integer literal" */
+ tFLOAT = 314, /* "float literal" */
+ tCHAR = 315, /* "character literal" */
+ tXSTRING = 316, /* tXSTRING */
+ tREGEXP = 317, /* tREGEXP */
+ tSTRING = 318, /* tSTRING */
+ tSTRING_PART = 319, /* tSTRING_PART */
+ tSTRING_MID = 320, /* tSTRING_MID */
+ tNTH_REF = 321, /* tNTH_REF */
+ tBACK_REF = 322, /* tBACK_REF */
+ tREGEXP_END = 323, /* tREGEXP_END */
+ tNUMPARAM = 324, /* "numbered parameter" */
+ tUPLUS = 325, /* "unary plus" */
+ tUMINUS = 326, /* "unary minus" */
+ tCMP = 327, /* "<=>" */
+ tEQ = 328, /* "==" */
+ tEQQ = 329, /* "===" */
+ tNEQ = 330, /* "!=" */
+ tGEQ = 331, /* ">=" */
+ tLEQ = 332, /* "<=" */
+ tANDOP = 333, /* "&&" */
+ tOROP = 334, /* "||" */
+ tMATCH = 335, /* "=~" */
+ tNMATCH = 336, /* "!~" */
+ tDOT2 = 337, /* ".." */
+ tDOT3 = 338, /* "..." */
+ tBDOT2 = 339, /* tBDOT2 */
+ tBDOT3 = 340, /* tBDOT3 */
+ tAREF = 341, /* tAREF */
+ tASET = 342, /* tASET */
+ tLSHFT = 343, /* "<<" */
+ tRSHFT = 344, /* ">>" */
+ tCOLON2 = 345, /* "::" */
+ tCOLON3 = 346, /* tCOLON3 */
+ tOP_ASGN = 347, /* tOP_ASGN */
+ tASSOC = 348, /* "=>" */
+ tLPAREN = 349, /* tLPAREN */
+ tLPAREN_ARG = 350, /* "(" */
+ tRPAREN = 351, /* ")" */
+ tLBRACK = 352, /* "[" */
+ tLBRACE = 353, /* tLBRACE */
+ tLBRACE_ARG = 354, /* "{" */
+ tSTAR = 355, /* "*" */
+ tPOW = 356, /* tPOW */
+ tDSTAR = 357, /* "**" */
+ tAMPER = 358, /* "&" */
+ tLAMBDA = 359, /* "->" */
+ tANDDOT = 360, /* "&." */
+ tSYMBEG = 361, /* "symbol" */
+ tSTRING_BEG = 362, /* "string literal" */
+ tXSTRING_BEG = 363, /* tXSTRING_BEG */
+ tSTRING_DVAR = 364, /* tSTRING_DVAR */
+ tREGEXP_BEG = 365, /* tREGEXP_BEG */
+ tWORDS_BEG = 366, /* tWORDS_BEG */
+ tSYMBOLS_BEG = 367, /* tSYMBOLS_BEG */
+ tLAMBEG = 368, /* tLAMBEG */
+ tHEREDOC_BEG = 369, /* "here document" */
+ tHEREDOC_END = 370, /* tHEREDOC_END */
+ tLITERAL_DELIM = 371, /* tLITERAL_DELIM */
+ tHD_LITERAL_DELIM = 372, /* tHD_LITERAL_DELIM */
+ tHD_STRING_PART = 373, /* tHD_STRING_PART */
+ tHD_STRING_MID = 374, /* tHD_STRING_MID */
+ tLOWEST = 375, /* tLOWEST */
+ tUMINUS_NUM = 376, /* tUMINUS_NUM */
+ tLAST_TOKEN = 377 /* tLAST_TOKEN */
+ };
+ typedef enum yytokentype yytoken_kind_t;
+#endif
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+union YYSTYPE
+{
+#line 2004 "mrbgems/mruby-compiler/core/parse.y"
+
+ node *nd;
+ mrb_sym id;
+ int num;
+ stack_type stack;
+ const struct vtable *vars;
+
+#line 2240 "mrbgems/mruby-compiler/core/y.tab.c"
+
+};
+typedef union YYSTYPE YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+/* Location type. */
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE YYLTYPE;
+struct YYLTYPE
+{
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+};
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+
+int yyparse (parser_state *p);
+
+
+
+
+/* Symbol kind. */
+enum yysymbol_kind_t
+{
+ YYSYMBOL_YYEMPTY = -2,
+ YYSYMBOL_YYEOF = 0, /* "end of file" */
+ YYSYMBOL_YYerror = 1, /* error */
+ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */
+ YYSYMBOL_keyword_class = 3, /* "'class'" */
+ YYSYMBOL_keyword_module = 4, /* "'module'" */
+ YYSYMBOL_keyword_def = 5, /* "'def'" */
+ YYSYMBOL_keyword_begin = 6, /* "'begin'" */
+ YYSYMBOL_keyword_if = 7, /* "'if'" */
+ YYSYMBOL_keyword_unless = 8, /* "'unless'" */
+ YYSYMBOL_keyword_while = 9, /* "'while'" */
+ YYSYMBOL_keyword_until = 10, /* "'until'" */
+ YYSYMBOL_keyword_for = 11, /* "'for'" */
+ YYSYMBOL_keyword_undef = 12, /* "'undef'" */
+ YYSYMBOL_keyword_rescue = 13, /* "'rescue'" */
+ YYSYMBOL_keyword_ensure = 14, /* "'ensure'" */
+ YYSYMBOL_keyword_end = 15, /* "'end'" */
+ YYSYMBOL_keyword_then = 16, /* "'then'" */
+ YYSYMBOL_keyword_elsif = 17, /* "'elsif'" */
+ YYSYMBOL_keyword_else = 18, /* "'else'" */
+ YYSYMBOL_keyword_case = 19, /* "'case'" */
+ YYSYMBOL_keyword_when = 20, /* "'when'" */
+ YYSYMBOL_keyword_break = 21, /* "'break'" */
+ YYSYMBOL_keyword_next = 22, /* "'next'" */
+ YYSYMBOL_keyword_redo = 23, /* "'redo'" */
+ YYSYMBOL_keyword_retry = 24, /* "'retry'" */
+ YYSYMBOL_keyword_in = 25, /* "'in'" */
+ YYSYMBOL_keyword_do = 26, /* "'do'" */
+ YYSYMBOL_keyword_do_cond = 27, /* "'do' for condition" */
+ YYSYMBOL_keyword_do_block = 28, /* "'do' for block" */
+ YYSYMBOL_keyword_do_LAMBDA = 29, /* "'do' for lambda" */
+ YYSYMBOL_keyword_return = 30, /* "'return'" */
+ YYSYMBOL_keyword_yield = 31, /* "'yield'" */
+ YYSYMBOL_keyword_super = 32, /* "'super'" */
+ YYSYMBOL_keyword_self = 33, /* "'self'" */
+ YYSYMBOL_keyword_nil = 34, /* "'nil'" */
+ YYSYMBOL_keyword_true = 35, /* "'true'" */
+ YYSYMBOL_keyword_false = 36, /* "'false'" */
+ YYSYMBOL_keyword_and = 37, /* "'and'" */
+ YYSYMBOL_keyword_or = 38, /* "'or'" */
+ YYSYMBOL_keyword_not = 39, /* "'not'" */
+ YYSYMBOL_modifier_if = 40, /* "'if' modifier" */
+ YYSYMBOL_modifier_unless = 41, /* "'unless' modifier" */
+ YYSYMBOL_modifier_while = 42, /* "'while' modifier" */
+ YYSYMBOL_modifier_until = 43, /* "'until' modifier" */
+ YYSYMBOL_modifier_rescue = 44, /* "'rescue' modifier" */
+ YYSYMBOL_keyword_alias = 45, /* "'alias'" */
+ YYSYMBOL_keyword_BEGIN = 46, /* "'BEGIN'" */
+ YYSYMBOL_keyword_END = 47, /* "'END'" */
+ YYSYMBOL_keyword__LINE__ = 48, /* "'__LINE__'" */
+ YYSYMBOL_keyword__FILE__ = 49, /* "'__FILE__'" */
+ YYSYMBOL_keyword__ENCODING__ = 50, /* "'__ENCODING__'" */
+ YYSYMBOL_tIDENTIFIER = 51, /* "local variable or method" */
+ YYSYMBOL_tFID = 52, /* "method" */
+ YYSYMBOL_tGVAR = 53, /* "global variable" */
+ YYSYMBOL_tIVAR = 54, /* "instance variable" */
+ YYSYMBOL_tCONSTANT = 55, /* "constant" */
+ YYSYMBOL_tCVAR = 56, /* "class variable" */
+ YYSYMBOL_tLABEL_TAG = 57, /* "label" */
+ YYSYMBOL_tINTEGER = 58, /* "integer literal" */
+ YYSYMBOL_tFLOAT = 59, /* "float literal" */
+ YYSYMBOL_tCHAR = 60, /* "character literal" */
+ YYSYMBOL_tXSTRING = 61, /* tXSTRING */
+ YYSYMBOL_tREGEXP = 62, /* tREGEXP */
+ YYSYMBOL_tSTRING = 63, /* tSTRING */
+ YYSYMBOL_tSTRING_PART = 64, /* tSTRING_PART */
+ YYSYMBOL_tSTRING_MID = 65, /* tSTRING_MID */
+ YYSYMBOL_tNTH_REF = 66, /* tNTH_REF */
+ YYSYMBOL_tBACK_REF = 67, /* tBACK_REF */
+ YYSYMBOL_tREGEXP_END = 68, /* tREGEXP_END */
+ YYSYMBOL_tNUMPARAM = 69, /* "numbered parameter" */
+ YYSYMBOL_tUPLUS = 70, /* "unary plus" */
+ YYSYMBOL_tUMINUS = 71, /* "unary minus" */
+ YYSYMBOL_tCMP = 72, /* "<=>" */
+ YYSYMBOL_tEQ = 73, /* "==" */
+ YYSYMBOL_tEQQ = 74, /* "===" */
+ YYSYMBOL_tNEQ = 75, /* "!=" */
+ YYSYMBOL_tGEQ = 76, /* ">=" */
+ YYSYMBOL_tLEQ = 77, /* "<=" */
+ YYSYMBOL_tANDOP = 78, /* "&&" */
+ YYSYMBOL_tOROP = 79, /* "||" */
+ YYSYMBOL_tMATCH = 80, /* "=~" */
+ YYSYMBOL_tNMATCH = 81, /* "!~" */
+ YYSYMBOL_tDOT2 = 82, /* ".." */
+ YYSYMBOL_tDOT3 = 83, /* "..." */
+ YYSYMBOL_tBDOT2 = 84, /* tBDOT2 */
+ YYSYMBOL_tBDOT3 = 85, /* tBDOT3 */
+ YYSYMBOL_tAREF = 86, /* tAREF */
+ YYSYMBOL_tASET = 87, /* tASET */
+ YYSYMBOL_tLSHFT = 88, /* "<<" */
+ YYSYMBOL_tRSHFT = 89, /* ">>" */
+ YYSYMBOL_tCOLON2 = 90, /* "::" */
+ YYSYMBOL_tCOLON3 = 91, /* tCOLON3 */
+ YYSYMBOL_tOP_ASGN = 92, /* tOP_ASGN */
+ YYSYMBOL_tASSOC = 93, /* "=>" */
+ YYSYMBOL_tLPAREN = 94, /* tLPAREN */
+ YYSYMBOL_tLPAREN_ARG = 95, /* "(" */
+ YYSYMBOL_tRPAREN = 96, /* ")" */
+ YYSYMBOL_tLBRACK = 97, /* "[" */
+ YYSYMBOL_tLBRACE = 98, /* tLBRACE */
+ YYSYMBOL_tLBRACE_ARG = 99, /* "{" */
+ YYSYMBOL_tSTAR = 100, /* "*" */
+ YYSYMBOL_tPOW = 101, /* tPOW */
+ YYSYMBOL_tDSTAR = 102, /* "**" */
+ YYSYMBOL_tAMPER = 103, /* "&" */
+ YYSYMBOL_tLAMBDA = 104, /* "->" */
+ YYSYMBOL_tANDDOT = 105, /* "&." */
+ YYSYMBOL_tSYMBEG = 106, /* "symbol" */
+ YYSYMBOL_tSTRING_BEG = 107, /* "string literal" */
+ YYSYMBOL_tXSTRING_BEG = 108, /* tXSTRING_BEG */
+ YYSYMBOL_tSTRING_DVAR = 109, /* tSTRING_DVAR */
+ YYSYMBOL_tREGEXP_BEG = 110, /* tREGEXP_BEG */
+ YYSYMBOL_tWORDS_BEG = 111, /* tWORDS_BEG */
+ YYSYMBOL_tSYMBOLS_BEG = 112, /* tSYMBOLS_BEG */
+ YYSYMBOL_tLAMBEG = 113, /* tLAMBEG */
+ YYSYMBOL_tHEREDOC_BEG = 114, /* "here document" */
+ YYSYMBOL_tHEREDOC_END = 115, /* tHEREDOC_END */
+ YYSYMBOL_tLITERAL_DELIM = 116, /* tLITERAL_DELIM */
+ YYSYMBOL_tHD_LITERAL_DELIM = 117, /* tHD_LITERAL_DELIM */
+ YYSYMBOL_tHD_STRING_PART = 118, /* tHD_STRING_PART */
+ YYSYMBOL_tHD_STRING_MID = 119, /* tHD_STRING_MID */
+ YYSYMBOL_tLOWEST = 120, /* tLOWEST */
+ YYSYMBOL_121_ = 121, /* '=' */
+ YYSYMBOL_122_ = 122, /* '?' */
+ YYSYMBOL_123_ = 123, /* ':' */
+ YYSYMBOL_124_ = 124, /* '>' */
+ YYSYMBOL_125_ = 125, /* '<' */
+ YYSYMBOL_126_ = 126, /* '|' */
+ YYSYMBOL_127_ = 127, /* '^' */
+ YYSYMBOL_128_ = 128, /* '&' */
+ YYSYMBOL_129_ = 129, /* '+' */
+ YYSYMBOL_130_ = 130, /* '-' */
+ YYSYMBOL_131_ = 131, /* '*' */
+ YYSYMBOL_132_ = 132, /* '/' */
+ YYSYMBOL_133_ = 133, /* '%' */
+ YYSYMBOL_tUMINUS_NUM = 134, /* tUMINUS_NUM */
+ YYSYMBOL_135_ = 135, /* '!' */
+ YYSYMBOL_136_ = 136, /* '~' */
+ YYSYMBOL_tLAST_TOKEN = 137, /* tLAST_TOKEN */
+ YYSYMBOL_138_ = 138, /* '{' */
+ YYSYMBOL_139_ = 139, /* '}' */
+ YYSYMBOL_140_ = 140, /* '[' */
+ YYSYMBOL_141_ = 141, /* ']' */
+ YYSYMBOL_142_ = 142, /* ',' */
+ YYSYMBOL_143_ = 143, /* '`' */
+ YYSYMBOL_144_ = 144, /* '(' */
+ YYSYMBOL_145_ = 145, /* ')' */
+ YYSYMBOL_146_ = 146, /* ';' */
+ YYSYMBOL_147_ = 147, /* '.' */
+ YYSYMBOL_148_n_ = 148, /* '\n' */
+ YYSYMBOL_YYACCEPT = 149, /* $accept */
+ YYSYMBOL_150_1 = 150, /* $@1 */
+ YYSYMBOL_program = 151, /* program */
+ YYSYMBOL_top_compstmt = 152, /* top_compstmt */
+ YYSYMBOL_top_stmts = 153, /* top_stmts */
+ YYSYMBOL_top_stmt = 154, /* top_stmt */
+ YYSYMBOL_155_2 = 155, /* @2 */
+ YYSYMBOL_bodystmt = 156, /* bodystmt */
+ YYSYMBOL_compstmt = 157, /* compstmt */
+ YYSYMBOL_stmts = 158, /* stmts */
+ YYSYMBOL_159_3 = 159, /* $@3 */
+ YYSYMBOL_stmt = 160, /* stmt */
+ YYSYMBOL_command_asgn = 161, /* command_asgn */
+ YYSYMBOL_command_rhs = 162, /* command_rhs */
+ YYSYMBOL_expr = 163, /* expr */
+ YYSYMBOL_164_4 = 164, /* $@4 */
+ YYSYMBOL_165_5 = 165, /* $@5 */
+ YYSYMBOL_defn_head = 166, /* defn_head */
+ YYSYMBOL_167_6 = 167, /* $@6 */
+ YYSYMBOL_defs_head = 168, /* defs_head */
+ YYSYMBOL_expr_value = 169, /* expr_value */
+ YYSYMBOL_command_call = 170, /* command_call */
+ YYSYMBOL_block_command = 171, /* block_command */
+ YYSYMBOL_172_7 = 172, /* $@7 */
+ YYSYMBOL_cmd_brace_block = 173, /* cmd_brace_block */
+ YYSYMBOL_command = 174, /* command */
+ YYSYMBOL_mlhs = 175, /* mlhs */
+ YYSYMBOL_mlhs_inner = 176, /* mlhs_inner */
+ YYSYMBOL_mlhs_basic = 177, /* mlhs_basic */
+ YYSYMBOL_mlhs_item = 178, /* mlhs_item */
+ YYSYMBOL_mlhs_list = 179, /* mlhs_list */
+ YYSYMBOL_mlhs_post = 180, /* mlhs_post */
+ YYSYMBOL_mlhs_node = 181, /* mlhs_node */
+ YYSYMBOL_lhs = 182, /* lhs */
+ YYSYMBOL_cname = 183, /* cname */
+ YYSYMBOL_cpath = 184, /* cpath */
+ YYSYMBOL_fname = 185, /* fname */
+ YYSYMBOL_fsym = 186, /* fsym */
+ YYSYMBOL_undef_list = 187, /* undef_list */
+ YYSYMBOL_188_8 = 188, /* $@8 */
+ YYSYMBOL_op = 189, /* op */
+ YYSYMBOL_reswords = 190, /* reswords */
+ YYSYMBOL_arg = 191, /* arg */
+ YYSYMBOL_aref_args = 192, /* aref_args */
+ YYSYMBOL_arg_rhs = 193, /* arg_rhs */
+ YYSYMBOL_paren_args = 194, /* paren_args */
+ YYSYMBOL_opt_paren_args = 195, /* opt_paren_args */
+ YYSYMBOL_opt_call_args = 196, /* opt_call_args */
+ YYSYMBOL_call_args = 197, /* call_args */
+ YYSYMBOL_198_9 = 198, /* @9 */
+ YYSYMBOL_command_args = 199, /* command_args */
+ YYSYMBOL_block_arg = 200, /* block_arg */
+ YYSYMBOL_opt_block_arg = 201, /* opt_block_arg */
+ YYSYMBOL_comma = 202, /* comma */
+ YYSYMBOL_args = 203, /* args */
+ YYSYMBOL_mrhs = 204, /* mrhs */
+ YYSYMBOL_primary = 205, /* primary */
+ YYSYMBOL_206_10 = 206, /* @10 */
+ YYSYMBOL_207_11 = 207, /* @11 */
+ YYSYMBOL_208_12 = 208, /* $@12 */
+ YYSYMBOL_209_13 = 209, /* $@13 */
+ YYSYMBOL_210_14 = 210, /* @14 */
+ YYSYMBOL_211_15 = 211, /* @15 */
+ YYSYMBOL_212_16 = 212, /* $@16 */
+ YYSYMBOL_213_17 = 213, /* $@17 */
+ YYSYMBOL_214_18 = 214, /* $@18 */
+ YYSYMBOL_215_19 = 215, /* $@19 */
+ YYSYMBOL_216_20 = 216, /* $@20 */
+ YYSYMBOL_217_21 = 217, /* $@21 */
+ YYSYMBOL_218_22 = 218, /* @22 */
+ YYSYMBOL_219_23 = 219, /* @23 */
+ YYSYMBOL_220_24 = 220, /* @24 */
+ YYSYMBOL_221_25 = 221, /* @25 */
+ YYSYMBOL_primary_value = 222, /* primary_value */
+ YYSYMBOL_then = 223, /* then */
+ YYSYMBOL_do = 224, /* do */
+ YYSYMBOL_if_tail = 225, /* if_tail */
+ YYSYMBOL_opt_else = 226, /* opt_else */
+ YYSYMBOL_for_var = 227, /* for_var */
+ YYSYMBOL_f_margs = 228, /* f_margs */
+ YYSYMBOL_229_26 = 229, /* $@26 */
+ YYSYMBOL_block_args_tail = 230, /* block_args_tail */
+ YYSYMBOL_opt_block_args_tail = 231, /* opt_block_args_tail */
+ YYSYMBOL_block_param = 232, /* block_param */
+ YYSYMBOL_opt_block_param = 233, /* opt_block_param */
+ YYSYMBOL_234_27 = 234, /* $@27 */
+ YYSYMBOL_block_param_def = 235, /* block_param_def */
+ YYSYMBOL_opt_bv_decl = 236, /* opt_bv_decl */
+ YYSYMBOL_bv_decls = 237, /* bv_decls */
+ YYSYMBOL_bvar = 238, /* bvar */
+ YYSYMBOL_f_larglist = 239, /* f_larglist */
+ YYSYMBOL_lambda_body = 240, /* lambda_body */
+ YYSYMBOL_241_28 = 241, /* @28 */
+ YYSYMBOL_do_block = 242, /* do_block */
+ YYSYMBOL_block_call = 243, /* block_call */
+ YYSYMBOL_method_call = 244, /* method_call */
+ YYSYMBOL_245_29 = 245, /* @29 */
+ YYSYMBOL_brace_block = 246, /* brace_block */
+ YYSYMBOL_247_30 = 247, /* @30 */
+ YYSYMBOL_case_body = 248, /* case_body */
+ YYSYMBOL_cases = 249, /* cases */
+ YYSYMBOL_in_clauses = 250, /* in_clauses */
+ YYSYMBOL_251_31 = 251, /* $@31 */
+ YYSYMBOL_252_32 = 252, /* $@32 */
+ YYSYMBOL_253_33 = 253, /* $@33 */
+ YYSYMBOL_p_expr = 254, /* p_expr */
+ YYSYMBOL_p_args_head = 255, /* p_args_head */
+ YYSYMBOL_p_args_post = 256, /* p_args_post */
+ YYSYMBOL_p_as = 257, /* p_as */
+ YYSYMBOL_p_alt = 258, /* p_alt */
+ YYSYMBOL_p_value = 259, /* p_value */
+ YYSYMBOL_p_array = 260, /* p_array */
+ YYSYMBOL_p_array_body = 261, /* p_array_body */
+ YYSYMBOL_p_array_elems = 262, /* p_array_elems */
+ YYSYMBOL_p_rest = 263, /* p_rest */
+ YYSYMBOL_p_const = 264, /* p_const */
+ YYSYMBOL_p_hash = 265, /* p_hash */
+ YYSYMBOL_p_hash_body = 266, /* p_hash_body */
+ YYSYMBOL_p_hash_elems = 267, /* p_hash_elems */
+ YYSYMBOL_p_hash_elem = 268, /* p_hash_elem */
+ YYSYMBOL_p_kwrest = 269, /* p_kwrest */
+ YYSYMBOL_p_var = 270, /* p_var */
+ YYSYMBOL_opt_rescue = 271, /* opt_rescue */
+ YYSYMBOL_exc_list = 272, /* exc_list */
+ YYSYMBOL_exc_var = 273, /* exc_var */
+ YYSYMBOL_opt_ensure = 274, /* opt_ensure */
+ YYSYMBOL_literal = 275, /* literal */
+ YYSYMBOL_string = 276, /* string */
+ YYSYMBOL_string_fragment = 277, /* string_fragment */
+ YYSYMBOL_string_rep = 278, /* string_rep */
+ YYSYMBOL_string_interp = 279, /* string_interp */
+ YYSYMBOL_280_34 = 280, /* @34 */
+ YYSYMBOL_xstring = 281, /* xstring */
+ YYSYMBOL_regexp = 282, /* regexp */
+ YYSYMBOL_heredoc = 283, /* heredoc */
+ YYSYMBOL_heredoc_bodies = 284, /* heredoc_bodies */
+ YYSYMBOL_heredoc_body = 285, /* heredoc_body */
+ YYSYMBOL_heredoc_string_rep = 286, /* heredoc_string_rep */
+ YYSYMBOL_heredoc_string_interp = 287, /* heredoc_string_interp */
+ YYSYMBOL_288_35 = 288, /* @35 */
+ YYSYMBOL_words = 289, /* words */
+ YYSYMBOL_symbol = 290, /* symbol */
+ YYSYMBOL_basic_symbol = 291, /* basic_symbol */
+ YYSYMBOL_sym = 292, /* sym */
+ YYSYMBOL_symbols = 293, /* symbols */
+ YYSYMBOL_numeric = 294, /* numeric */
+ YYSYMBOL_variable = 295, /* variable */
+ YYSYMBOL_var_lhs = 296, /* var_lhs */
+ YYSYMBOL_var_ref = 297, /* var_ref */
+ YYSYMBOL_backref = 298, /* backref */
+ YYSYMBOL_superclass = 299, /* superclass */
+ YYSYMBOL_300_36 = 300, /* $@36 */
+ YYSYMBOL_f_opt_arglist_paren = 301, /* f_opt_arglist_paren */
+ YYSYMBOL_f_arglist_paren = 302, /* f_arglist_paren */
+ YYSYMBOL_f_arglist = 303, /* f_arglist */
+ YYSYMBOL_f_label = 304, /* f_label */
+ YYSYMBOL_f_kw = 305, /* f_kw */
+ YYSYMBOL_f_block_kw = 306, /* f_block_kw */
+ YYSYMBOL_f_block_kwarg = 307, /* f_block_kwarg */
+ YYSYMBOL_f_kwarg = 308, /* f_kwarg */
+ YYSYMBOL_kwrest_mark = 309, /* kwrest_mark */
+ YYSYMBOL_f_kwrest = 310, /* f_kwrest */
+ YYSYMBOL_args_tail = 311, /* args_tail */
+ YYSYMBOL_opt_args_tail = 312, /* opt_args_tail */
+ YYSYMBOL_f_args = 313, /* f_args */
+ YYSYMBOL_f_bad_arg = 314, /* f_bad_arg */
+ YYSYMBOL_f_norm_arg = 315, /* f_norm_arg */
+ YYSYMBOL_f_arg_item = 316, /* f_arg_item */
+ YYSYMBOL_317_37 = 317, /* @37 */
+ YYSYMBOL_f_arg = 318, /* f_arg */
+ YYSYMBOL_f_opt_asgn = 319, /* f_opt_asgn */
+ YYSYMBOL_f_opt = 320, /* f_opt */
+ YYSYMBOL_f_block_opt = 321, /* f_block_opt */
+ YYSYMBOL_f_block_optarg = 322, /* f_block_optarg */
+ YYSYMBOL_f_optarg = 323, /* f_optarg */
+ YYSYMBOL_restarg_mark = 324, /* restarg_mark */
+ YYSYMBOL_f_rest_arg = 325, /* f_rest_arg */
+ YYSYMBOL_blkarg_mark = 326, /* blkarg_mark */
+ YYSYMBOL_f_block_arg = 327, /* f_block_arg */
+ YYSYMBOL_opt_f_block_arg = 328, /* opt_f_block_arg */
+ YYSYMBOL_singleton = 329, /* singleton */
+ YYSYMBOL_330_38 = 330, /* $@38 */
+ YYSYMBOL_assoc_list = 331, /* assoc_list */
+ YYSYMBOL_assocs = 332, /* assocs */
+ YYSYMBOL_assoc = 333, /* assoc */
+ YYSYMBOL_operation = 334, /* operation */
+ YYSYMBOL_operation2 = 335, /* operation2 */
+ YYSYMBOL_operation3 = 336, /* operation3 */
+ YYSYMBOL_dot_or_colon = 337, /* dot_or_colon */
+ YYSYMBOL_call_op = 338, /* call_op */
+ YYSYMBOL_call_op2 = 339, /* call_op2 */
+ YYSYMBOL_opt_terms = 340, /* opt_terms */
+ YYSYMBOL_opt_nl = 341, /* opt_nl */
+ YYSYMBOL_rparen = 342, /* rparen */
+ YYSYMBOL_trailer = 343, /* trailer */
+ YYSYMBOL_term = 344, /* term */
+ YYSYMBOL_nl = 345, /* nl */
+ YYSYMBOL_terms = 346, /* terms */
+ YYSYMBOL_none = 347 /* none */
+};
+typedef enum yysymbol_kind_t yysymbol_kind_t;
+
+
+
+
+#ifdef short
+# undef short
+#endif
+
+/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
+ <limits.h> and (if available) <stdint.h> are included
+ so that the code can choose integer types of a good width. */
+
+#ifndef __PTRDIFF_MAX__
+# include <limits.h> /* INFRINGES ON USER NAME SPACE */
+# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+# include <stdint.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_STDINT_H
+# endif
+#endif
+
+/* Narrow types that promote to a signed type and that can represent a
+ signed or unsigned integer of at least N bits. In tables they can
+ save space and decrease cache pressure. Promoting to a signed type
+ helps avoid bugs in integer arithmetic. */
+
+#ifdef __INT_LEAST8_MAX__
+typedef __INT_LEAST8_TYPE__ yytype_int8;
+#elif defined YY_STDINT_H
+typedef int_least8_t yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef __INT_LEAST16_MAX__
+typedef __INT_LEAST16_TYPE__ yytype_int16;
+#elif defined YY_STDINT_H
+typedef int_least16_t yytype_int16;
+#else
+typedef short yytype_int16;
+#endif
+
+/* Work around bug in HP-UX 11.23, which defines these macros
+ incorrectly for preprocessor constants. This workaround can likely
+ be removed in 2023, as HPE has promised support for HP-UX 11.23
+ (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of
+ <https://h20195.www2.hpe.com/V2/getpdf.aspx/4AA4-7673ENW.pdf>. */
+#ifdef __hpux
+# undef UINT_LEAST8_MAX
+# undef UINT_LEAST16_MAX
+# define UINT_LEAST8_MAX 255
+# define UINT_LEAST16_MAX 65535
+#endif
+
+#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST8_TYPE__ yytype_uint8;
+#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
+ && UINT_LEAST8_MAX <= INT_MAX)
+typedef uint_least8_t yytype_uint8;
+#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
+typedef unsigned char yytype_uint8;
+#else
+typedef short yytype_uint8;
+#endif
+
+#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST16_TYPE__ yytype_uint16;
+#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
+ && UINT_LEAST16_MAX <= INT_MAX)
+typedef uint_least16_t yytype_uint16;
+#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
+typedef unsigned short yytype_uint16;
+#else
+typedef int yytype_uint16;
+#endif
+
+#ifndef YYPTRDIFF_T
+# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
+# define YYPTRDIFF_T __PTRDIFF_TYPE__
+# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
+# elif defined PTRDIFF_MAX
+# ifndef ptrdiff_t
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# endif
+# define YYPTRDIFF_T ptrdiff_t
+# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
+# else
+# define YYPTRDIFF_T long
+# define YYPTRDIFF_MAXIMUM LONG_MAX
+# endif
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM \
+ YY_CAST (YYPTRDIFF_T, \
+ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \
+ ? YYPTRDIFF_MAXIMUM \
+ : YY_CAST (YYSIZE_T, -1)))
+
+#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
+
+
+/* Stored state numbers (used for stacks). */
+typedef yytype_int16 yy_state_t;
+
+/* State numbers in computations. */
+typedef int yy_state_fast_t;
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+
+#ifndef YY_ATTRIBUTE_PURE
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+# define YY_ATTRIBUTE_PURE
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+# define YY_ATTRIBUTE_UNUSED
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YY_USE(E) ((void) (E))
+#else
+# define YY_USE(E) /* empty */
+#endif
+
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__
+# if __GNUC__ * 100 + __GNUC_MINOR__ < 407
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")
+# else
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# endif
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END \
+ _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
+
+#define YY_ASSERT(E) ((void) (0 && (E)))
+
+#if 1
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's 'empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* 1 */
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yy_state_t yyss_alloc;
+ YYSTYPE yyvs_alloc;
+ YYLTYPE yyls_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE) \
+ + YYSIZEOF (YYLTYPE)) \
+ + 2 * YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYPTRDIFF_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / YYSIZEOF (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYPTRDIFF_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 106
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 13757
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 149
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 199
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 692
+/* YYNSTATES -- Number of states. */
+#define YYNSTATES 1204
+
+/* YYMAXUTOK -- Last valid token kind. */
+#define YYMAXUTOK 377
+
+
+/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex, with out-of-bounds checking. */
+#define YYTRANSLATE(YYX) \
+ (0 <= (YYX) && (YYX) <= YYMAXUTOK \
+ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \
+ : YYSYMBOL_YYUNDEF)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 148, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 135, 2, 2, 2, 133, 128, 2,
+ 144, 145, 131, 129, 142, 130, 147, 132, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 123, 146,
+ 125, 121, 124, 122, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 140, 2, 141, 127, 2, 143, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 138, 126, 139, 136, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+ 115, 116, 117, 118, 119, 120, 134, 137
+};
+
+#if YYDEBUG
+/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+static const yytype_int16 yyrline[] =
+{
+ 0, 2178, 2178, 2178, 2188, 2194, 2198, 2202, 2206, 2212,
+ 2214, 2213, 2227, 2253, 2259, 2263, 2267, 2271, 2277, 2277,
+ 2281, 2285, 2289, 2293, 2302, 2311, 2315, 2320, 2321, 2325,
+ 2329, 2333, 2337, 2340, 2344, 2348, 2352, 2356, 2360, 2365,
+ 2369, 2378, 2387, 2396, 2405, 2412, 2413, 2417, 2420, 2421,
+ 2425, 2429, 2433, 2437, 2437, 2443, 2443, 2449, 2452, 2462,
+ 2461, 2476, 2485, 2486, 2489, 2490, 2497, 2496, 2511, 2515,
+ 2520, 2524, 2529, 2533, 2538, 2542, 2546, 2550, 2554, 2560,
+ 2564, 2570, 2571, 2577, 2581, 2585, 2589, 2593, 2597, 2601,
+ 2605, 2609, 2613, 2619, 2620, 2626, 2630, 2636, 2640, 2646,
+ 2650, 2654, 2658, 2662, 2666, 2672, 2678, 2685, 2689, 2693,
+ 2697, 2701, 2705, 2711, 2717, 2722, 2728, 2732, 2735, 2739,
+ 2743, 2750, 2751, 2752, 2753, 2758, 2765, 2766, 2769, 2773,
+ 2773, 2779, 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787,
+ 2788, 2789, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797,
+ 2798, 2799, 2800, 2801, 2802, 2803, 2804, 2805, 2806, 2807,
+ 2808, 2811, 2811, 2811, 2812, 2812, 2813, 2813, 2813, 2814,
+ 2814, 2814, 2814, 2815, 2815, 2815, 2816, 2816, 2816, 2817,
+ 2817, 2817, 2817, 2818, 2818, 2818, 2818, 2819, 2819, 2819,
+ 2819, 2820, 2820, 2820, 2820, 2821, 2821, 2821, 2821, 2822,
+ 2822, 2825, 2829, 2833, 2837, 2841, 2845, 2849, 2854, 2859,
+ 2864, 2868, 2872, 2876, 2880, 2884, 2888, 2892, 2896, 2900,
+ 2904, 2908, 2912, 2916, 2920, 2924, 2928, 2932, 2936, 2940,
+ 2944, 2948, 2952, 2956, 2960, 2964, 2968, 2972, 2976, 2980,
+ 2984, 2988, 2992, 2996, 3000, 3004, 3008, 3012, 3021, 3030,
+ 3039, 3048, 3054, 3055, 3059, 3063, 3069, 3073, 3080, 3084,
+ 3093, 3110, 3111, 3114, 3115, 3116, 3120, 3124, 3130, 3135,
+ 3139, 3143, 3147, 3153, 3153, 3164, 3168, 3174, 3178, 3184,
+ 3187, 3192, 3196, 3200, 3205, 3209, 3215, 3220, 3224, 3230,
+ 3231, 3235, 3239, 3240, 3241, 3242, 3243, 3248, 3247, 3259,
+ 3263, 3258, 3268, 3268, 3272, 3276, 3280, 3284, 3288, 3292,
+ 3296, 3300, 3304, 3308, 3312, 3313, 3319, 3326, 3318, 3339,
+ 3347, 3355, 3355, 3355, 3362, 3362, 3362, 3369, 3375, 3379,
+ 3388, 3397, 3407, 3409, 3406, 3418, 3416, 3434, 3439, 3432,
+ 3456, 3454, 3470, 3480, 3491, 3495, 3499, 3503, 3509, 3516,
+ 3517, 3518, 3521, 3522, 3525, 3526, 3534, 3535, 3541, 3545,
+ 3548, 3552, 3556, 3560, 3565, 3569, 3573, 3577, 3583, 3582,
+ 3592, 3596, 3600, 3604, 3610, 3615, 3620, 3624, 3628, 3632,
+ 3636, 3640, 3644, 3648, 3652, 3656, 3660, 3664, 3668, 3672,
+ 3676, 3682, 3687, 3694, 3694, 3698, 3703, 3709, 3713, 3719,
+ 3720, 3723, 3728, 3731, 3735, 3741, 3745, 3752, 3751, 3768,
+ 3773, 3777, 3782, 3789, 3793, 3797, 3801, 3805, 3809, 3813,
+ 3817, 3821, 3828, 3827, 3842, 3841, 3857, 3865, 3874, 3879,
+ 3883, 3883, 3888, 3888, 3893, 3893, 3903, 3904, 3908, 3912,
+ 3916, 3920, 3924, 3929, 3934, 3942, 3946, 3953, 3957, 3963,
+ 3964, 3970, 3971, 3977, 3978, 3982, 3986, 3990, 3994, 3998,
+ 4002, 4006, 4007, 4008, 4015, 4019, 4026, 4031, 4036, 4041,
+ 4046, 4051, 4059, 4063, 4070, 4074, 4082, 4086, 4090, 4097,
+ 4101, 4108, 4112, 4116, 4123, 4127, 4136, 4141, 4149, 4153,
+ 4158, 4165, 4171, 4178, 4181, 4185, 4186, 4189, 4193, 4196,
+ 4200, 4203, 4204, 4205, 4206, 4209, 4210, 4216, 4221, 4226,
+ 4231, 4237, 4238, 4244, 4250, 4249, 4261, 4265, 4271, 4275,
+ 4281, 4290, 4301, 4304, 4305, 4308, 4314, 4320, 4321, 4324,
+ 4331, 4330, 4345, 4349, 4357, 4361, 4373, 4380, 4387, 4388,
+ 4389, 4390, 4391, 4395, 4401, 4405, 4413, 4414, 4415, 4419,
+ 4425, 4429, 4433, 4437, 4441, 4447, 4451, 4457, 4461, 4465,
+ 4469, 4473, 4477, 4481, 4489, 4496, 4502, 4503, 4507, 4511,
+ 4510, 4527, 4528, 4531, 4537, 4541, 4547, 4548, 4552, 4556,
+ 4562, 4568, 4576, 4582, 4589, 4595, 4602, 4606, 4612, 4616,
+ 4622, 4623, 4626, 4630, 4636, 4640, 4644, 4648, 4654, 4658,
+ 4663, 4668, 4672, 4676, 4680, 4684, 4688, 4692, 4696, 4700,
+ 4704, 4708, 4712, 4716, 4720, 4725, 4731, 4736, 4741, 4746,
+ 4751, 4758, 4762, 4769, 4774, 4773, 4785, 4789, 4795, 4803,
+ 4811, 4819, 4823, 4829, 4833, 4839, 4840, 4843, 4848, 4855,
+ 4856, 4859, 4863, 4867, 4873, 4877, 4881, 4887, 4893, 4893,
+ 4900, 4901, 4907, 4911, 4917, 4923, 4928, 4932, 4937, 4942,
+ 4958, 4963, 4969, 4970, 4971, 4974, 4975, 4976, 4977, 4980,
+ 4981, 4982, 4985, 4986, 4989, 4993, 4999, 5000, 5006, 5007,
+ 5010, 5011, 5014, 5017, 5018, 5019, 5022, 5023, 5026, 5031,
+ 5034, 5035, 5039
+};
+#endif
+
+/** Accessing symbol of state STATE. */
+#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
+
+#if 1
+/* The user-facing name of the symbol whose (internal) number is
+ YYSYMBOL. No bounds checking. */
+static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
+
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "\"end of file\"", "error", "\"invalid token\"", "\"'class'\"",
+ "\"'module'\"", "\"'def'\"", "\"'begin'\"", "\"'if'\"", "\"'unless'\"",
+ "\"'while'\"", "\"'until'\"", "\"'for'\"", "\"'undef'\"", "\"'rescue'\"",
+ "\"'ensure'\"", "\"'end'\"", "\"'then'\"", "\"'elsif'\"", "\"'else'\"",
+ "\"'case'\"", "\"'when'\"", "\"'break'\"", "\"'next'\"", "\"'redo'\"",
+ "\"'retry'\"", "\"'in'\"", "\"'do'\"", "\"'do' for condition\"",
+ "\"'do' for block\"", "\"'do' for lambda\"", "\"'return'\"",
+ "\"'yield'\"", "\"'super'\"", "\"'self'\"", "\"'nil'\"", "\"'true'\"",
+ "\"'false'\"", "\"'and'\"", "\"'or'\"", "\"'not'\"", "\"'if' modifier\"",
+ "\"'unless' modifier\"", "\"'while' modifier\"", "\"'until' modifier\"",
+ "\"'rescue' modifier\"", "\"'alias'\"", "\"'BEGIN'\"", "\"'END'\"",
+ "\"'__LINE__'\"", "\"'__FILE__'\"", "\"'__ENCODING__'\"",
+ "\"local variable or method\"", "\"method\"", "\"global variable\"",
+ "\"instance variable\"", "\"constant\"", "\"class variable\"",
+ "\"label\"", "\"integer literal\"", "\"float literal\"",
+ "\"character literal\"", "tXSTRING", "tREGEXP", "tSTRING",
+ "tSTRING_PART", "tSTRING_MID", "tNTH_REF", "tBACK_REF", "tREGEXP_END",
+ "\"numbered parameter\"", "\"unary plus\"", "\"unary minus\"", "\"<=>\"",
+ "\"==\"", "\"===\"", "\"!=\"", "\">=\"", "\"<=\"", "\"&&\"", "\"||\"",
+ "\"=~\"", "\"!~\"", "\"..\"", "\"...\"", "tBDOT2", "tBDOT3", "tAREF",
+ "tASET", "\"<<\"", "\">>\"", "\"::\"", "tCOLON3", "tOP_ASGN", "\"=>\"",
+ "tLPAREN", "\"(\"", "\")\"", "\"[\"", "tLBRACE", "\"{\"", "\"*\"",
+ "tPOW", "\"**\"", "\"&\"", "\"->\"", "\"&.\"", "\"symbol\"",
+ "\"string literal\"", "tXSTRING_BEG", "tSTRING_DVAR", "tREGEXP_BEG",
+ "tWORDS_BEG", "tSYMBOLS_BEG", "tLAMBEG", "\"here document\"",
+ "tHEREDOC_END", "tLITERAL_DELIM", "tHD_LITERAL_DELIM", "tHD_STRING_PART",
+ "tHD_STRING_MID", "tLOWEST", "'='", "'?'", "':'", "'>'", "'<'", "'|'",
+ "'^'", "'&'", "'+'", "'-'", "'*'", "'/'", "'%'", "tUMINUS_NUM", "'!'",
+ "'~'", "tLAST_TOKEN", "'{'", "'}'", "'['", "']'", "','", "'`'", "'('",
+ "')'", "';'", "'.'", "'\\n'", "$accept", "$@1", "program",
+ "top_compstmt", "top_stmts", "top_stmt", "@2", "bodystmt", "compstmt",
+ "stmts", "$@3", "stmt", "command_asgn", "command_rhs", "expr", "$@4",
+ "$@5", "defn_head", "$@6", "defs_head", "expr_value", "command_call",
+ "block_command", "$@7", "cmd_brace_block", "command", "mlhs",
+ "mlhs_inner", "mlhs_basic", "mlhs_item", "mlhs_list", "mlhs_post",
+ "mlhs_node", "lhs", "cname", "cpath", "fname", "fsym", "undef_list",
+ "$@8", "op", "reswords", "arg", "aref_args", "arg_rhs", "paren_args",
+ "opt_paren_args", "opt_call_args", "call_args", "@9", "command_args",
+ "block_arg", "opt_block_arg", "comma", "args", "mrhs", "primary", "@10",
+ "@11", "$@12", "$@13", "@14", "@15", "$@16", "$@17", "$@18", "$@19",
+ "$@20", "$@21", "@22", "@23", "@24", "@25", "primary_value", "then",
+ "do", "if_tail", "opt_else", "for_var", "f_margs", "$@26",
+ "block_args_tail", "opt_block_args_tail", "block_param",
+ "opt_block_param", "$@27", "block_param_def", "opt_bv_decl", "bv_decls",
+ "bvar", "f_larglist", "lambda_body", "@28", "do_block", "block_call",
+ "method_call", "@29", "brace_block", "@30", "case_body", "cases",
+ "in_clauses", "$@31", "$@32", "$@33", "p_expr", "p_args_head",
+ "p_args_post", "p_as", "p_alt", "p_value", "p_array", "p_array_body",
+ "p_array_elems", "p_rest", "p_const", "p_hash", "p_hash_body",
+ "p_hash_elems", "p_hash_elem", "p_kwrest", "p_var", "opt_rescue",
+ "exc_list", "exc_var", "opt_ensure", "literal", "string",
+ "string_fragment", "string_rep", "string_interp", "@34", "xstring",
+ "regexp", "heredoc", "heredoc_bodies", "heredoc_body",
+ "heredoc_string_rep", "heredoc_string_interp", "@35", "words", "symbol",
+ "basic_symbol", "sym", "symbols", "numeric", "variable", "var_lhs",
+ "var_ref", "backref", "superclass", "$@36", "f_opt_arglist_paren",
+ "f_arglist_paren", "f_arglist", "f_label", "f_kw", "f_block_kw",
+ "f_block_kwarg", "f_kwarg", "kwrest_mark", "f_kwrest", "args_tail",
+ "opt_args_tail", "f_args", "f_bad_arg", "f_norm_arg", "f_arg_item",
+ "@37", "f_arg", "f_opt_asgn", "f_opt", "f_block_opt", "f_block_optarg",
+ "f_optarg", "restarg_mark", "f_rest_arg", "blkarg_mark", "f_block_arg",
+ "opt_f_block_arg", "singleton", "$@38", "assoc_list", "assocs", "assoc",
+ "operation", "operation2", "operation3", "dot_or_colon", "call_op",
+ "call_op2", "opt_terms", "opt_nl", "rparen", "trailer", "term", "nl",
+ "terms", "none", YY_NULLPTR
+};
+
+static const char *
+yysymbol_name (yysymbol_kind_t yysymbol)
+{
+ return yytname[yysymbol];
+}
+#endif
+
+#define YYPACT_NINF (-975)
+
+#define yypact_value_is_default(Yyn) \
+ ((Yyn) == YYPACT_NINF)
+
+#define YYTABLE_NINF (-693)
+
+#define yytable_value_is_error(Yyn) \
+ ((Yyn) == YYTABLE_NINF)
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+static const yytype_int16 yypact[] =
+{
+ -975, 3710, 183, 8854, 10978, 11320, 7162, -975, 10624, 10624,
+ -975, -975, 11092, 8344, 6778, 9090, 9090, -975, -975, 9090,
+ 4231, 3370, -975, -975, -975, -975, 54, 8344, -975, 66,
+ -975, -975, -975, 7304, 3823, -975, -975, 7446, -975, -975,
+ -975, -975, -975, -975, -975, 210, 10742, 10742, 10742, 10742,
+ 109, 5891, 6010, 9562, 9916, 8626, -975, 8062, 1236, 893,
+ 314, 1249, 1252, -975, 447, 10860, 10742, -975, 857, -975,
+ 745, -975, 569, 2754, 2754, -975, -975, 173, 89, -975,
+ 106, 11206, -975, 136, 1909, 631, 667, 130, 41, -975,
+ 341, -975, -975, -975, -975, -975, -975, -975, -975, -975,
+ 211, 195, -975, 214, 87, -975, -975, -975, -975, -975,
+ -975, 180, 180, 54, 125, 498, -975, 10624, 187, 6129,
+ 556, 2225, 2225, -975, 215, -975, 691, -975, -975, 87,
+ -975, -975, -975, -975, -975, -975, -975, -975, -975, -975,
+ -975, -975, -975, -975, -975, -975, -975, -975, -975, -975,
+ -975, -975, -975, -975, -975, -975, -975, -975, 77, 143,
+ 149, 153, -975, -975, -975, -975, -975, -975, 164, 181,
+ 233, 247, -975, 248, -975, -975, -975, -975, -975, -975,
+ -975, -975, -975, -975, -975, -975, -975, -975, -975, -975,
+ -975, -975, -975, -975, -975, -975, -975, -975, -975, -975,
+ -975, -975, -975, -975, -975, -975, -975, -975, -975, 264,
+ 4923, 351, 569, 2754, 2754, 179, 261, 701, 220, 310,
+ 221, 179, 10624, 10624, 759, 365, -975, -975, 823, 404,
+ 21, 58, -975, -975, -975, -975, -975, -975, -975, -975,
+ -975, 8203, -975, -975, 298, -975, -975, -975, -975, -975,
+ -975, 857, -975, 951, -975, 439, -975, -975, 857, 3959,
+ 129, 10742, 10742, 10742, 10742, -975, 3465, -975, -975, 322,
+ 409, 322, -975, -975, -975, 9208, -975, -975, 9090, -975,
+ -975, -975, -975, 6778, 7016, -975, 334, 6248, -975, 891,
+ 379, 13606, 13606, 279, 8972, 5891, 355, 1572, 745, 857,
+ 402, -975, 6129, 857, 345, 1350, 1350, -975, 3465, 405,
+ 1350, -975, 491, 11434, 408, 950, 952, 981, 1713, -975,
+ -975, -975, -975, -975, 1327, -975, -975, -975, -975, -975,
+ -975, 966, 1331, -975, -975, 1244, -975, 872, -975, 1338,
+ -975, 1341, 452, 458, -975, -975, -975, -975, 6659, 10624,
+ 10624, 10624, 10624, 8972, 10624, 10624, 124, -975, -975, -975,
+ -975, 509, 857, -975, -975, -975, -975, -975, -975, -975,
+ 2841, 451, 459, 4923, 10742, -975, 441, 540, 453, -975,
+ 857, -975, -975, -975, 455, 10742, -975, 462, 549, 467,
+ 283, -975, -975, 516, 4923, -975, -975, 10034, -975, 5891,
+ 8740, 504, 10034, -975, 10742, 10742, 10742, 10742, 10742, 10742,
+ 10742, 10742, 10742, 10742, 10742, 10742, 10742, 10742, -975, 10742,
+ 10742, 10742, 10742, 10742, 10742, 10742, 10742, 10742, 10742, 10742,
+ 10742, 11712, -975, 9090, -975, 11798, -975, -975, 13002, -975,
+ -975, -975, -975, 10860, 10860, -975, 541, -975, 569, -975,
+ 1001, -975, -975, -975, -975, -975, -975, 11884, 9090, 11970,
+ 4923, 10624, -975, -975, -975, 635, 640, 244, 535, 547,
+ -975, 5069, 646, 10742, 12056, 9090, 12142, 10742, 10742, 5507,
+ 750, 750, 84, 12228, 9090, 12314, -975, 614, -975, 6248,
+ 435, -975, -975, 10152, 668, -975, 10742, 10742, 13544, 13544,
+ 13544, 10742, -975, -975, 9326, -975, 10742, -975, 9680, 6897,
+ 550, 857, 322, 322, -975, -975, 914, 571, -975, -975,
+ -975, 8344, 5626, 546, 12056, 12142, 10742, 745, 857, -975,
+ -975, 6540, 559, -975, -975, -975, 9798, -975, 857, 9916,
+ -975, -975, -975, 1001, 106, 11434, -975, 11434, 12400, 9090,
+ 12486, 2165, -975, -975, 590, -975, 1398, 6248, 966, -975,
+ -975, -975, -975, -975, -975, -975, 10742, 10742, -975, -975,
+ -975, -975, -975, -975, -975, -975, -975, -975, -975, -975,
+ 1453, 857, 857, 595, 10860, 727, 13544, 578, -975, -975,
+ -975, 59, -975, -975, 2966, -975, 13544, 2165, -975, -975,
+ 1242, -975, -975, -975, 10860, 729, 35, 10742, -975, 13260,
+ 322, -975, 857, 11434, 606, -975, -975, -975, 702, 628,
+ 2901, -975, -975, 1024, 263, 2044, 3556, 3556, 3556, 3556,
+ 1659, 1659, 13624, 3121, 3556, 3556, 13606, 13606, 1564, 1564,
+ 2044, 379, 13544, 1659, 1659, 1814, 1814, 1470, 542, 542,
+ 379, 379, 379, 4367, 7802, 4639, 7920, -975, 180, -975,
+ 611, 322, 291, -975, 342, -975, -975, 4095, -975, -975,
+ 2566, 35, 35, -975, 13074, -975, -975, -975, -975, -975,
+ 857, 10624, 4923, 757, 161, -975, 180, 624, 180, 751,
+ 914, 8485, -975, 10270, 755, -975, 10742, 10742, 604, -975,
+ 7564, 7683, 634, 346, 347, 755, -975, -975, -975, -975,
+ 55, 63, 641, 86, 105, 10624, 8344, 651, 2044, 779,
+ 13544, 327, -975, 13544, 13544, 13544, 1208, 10742, 3465, -975,
+ 322, 13544, -975, -975, -975, -975, 9444, 9680, -975, -975,
+ -975, 656, -975, -975, 131, 745, 857, 1350, 504, -975,
+ 757, 161, 659, 936, 1105, -975, 61, 2165, -975, 658,
+ -975, 379, 379, -975, -975, 336, 857, 666, -975, -975,
+ 2986, 765, 13136, -975, 753, 509, -975, 453, -975, 857,
+ -975, -975, 671, 678, 682, -975, 690, 753, 682, 789,
+ 13198, -975, -975, 2165, 4923, -975, -975, 13331, 10388, -975,
+ -975, 11434, 8972, 10860, 10742, 12572, 9090, 12658, -975, -975,
+ -975, 777, -975, -975, 782, 1383, 107, 800, 393, 801,
+ -975, 2304, 713, 46, -975, -975, 716, 763, -975, 728,
+ -975, -975, -975, -975, -975, -975, 797, 10860, 10860, -975,
+ 541, 468, 9326, 10860, 10860, -975, 541, 41, 173, 4923,
+ 6248, 35, -975, 857, 859, -975, -975, -975, -975, 13260,
+ -975, 784, -975, 5772, 858, -975, 10624, 863, -975, 10742,
+ 10742, 349, 10742, 10742, 871, 6394, 6394, 113, 750, -975,
+ -975, 536, -975, 10506, 5215, 13544, -975, 6897, 322, -975,
+ -975, -975, 615, 743, 989, 4923, 6248, -975, -975, -975,
+ 758, -975, 1560, 857, 10742, 10742, -975, -975, 2165, -975,
+ 1242, -975, 1242, -975, 1242, -975, -975, 10742, 10742, -975,
+ -975, -975, 11548, -975, 760, 453, 761, 11548, -975, 766,
+ 769, -975, 902, 10742, 13402, -975, -975, 13544, 4503, 4775,
+ 790, 360, 361, 2410, -975, -975, -975, -975, 791, 776,
+ 783, 777, -975, 799, 798, -975, -975, -975, -975, -975,
+ 807, 813, -975, 890, 2410, 2410, 901, 50, 10742, 10742,
+ -975, -975, -975, -975, -975, 10860, -975, -975, -975, -975,
+ -975, -975, -975, 945, 826, 6248, 4923, -975, -975, 11662,
+ 179, -975, -975, 6394, -975, -975, 179, -975, 10742, -975,
+ 953, 956, -975, 10624, 10624, 5361, 13544, 300, -975, 9680,
+ -975, 1608, 958, 827, 1582, 1582, 838, -975, 13544, 13544,
+ 682, 850, 682, 682, 13544, 13544, 869, 874, 947, 1064,
+ 578, -975, -975, 1963, -975, 1064, 2165, -975, 1242, -975,
+ -975, 13473, 469, -975, -975, 2304, 2410, -975, 50, -975,
+ 2410, -975, -975, 866, -975, -975, -975, -975, 13544, 13544,
+ -975, -975, -975, -975, 875, 996, 963, -975, 1097, 952,
+ 981, 4923, -975, 5069, -975, -975, 6394, 179, 179, 389,
+ -975, -975, -975, -975, 877, -975, -975, -975, -975, 882,
+ 882, 1582, 886, -975, 1242, -975, -975, -975, -975, -975,
+ -975, 12744, -975, 453, 578, -975, -975, 888, 892, 897,
+ -975, 903, 897, -975, 916, 922, -975, 866, 2410, -975,
+ -975, 1001, 12830, 9090, 12916, 640, 604, 1005, 5361, 5361,
+ 2044, -975, 1041, 1608, 1208, 1582, 882, 1582, 682, 921,
+ 923, -975, 2165, -975, 1242, -975, 1242, -975, 1242, -975,
+ -975, 2410, 2304, -975, 757, 161, 946, 711, 725, -975,
+ -975, -975, 389, 389, 594, -975, -975, 882, -975, 897,
+ 961, 897, 897, 967, -975, 615, 1074, 1079, 179, 1055,
+ 1059, -975, 1242, -975, -975, -975, 2410, -975, -975, 5361,
+ 10624, 10624, 897, 389, 179, 179, -975, -975, 5361, 5361,
+ 389, 389, -975, -975
+};
+
+/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE does not specify something else to do. Zero
+ means the default is an error. */
+static const yytype_int16 yydefact[] =
+{
+ 2, 0, 0, 0, 0, 0, 0, 297, 0, 0,
+ 321, 324, 0, 0, 678, 344, 345, 346, 347, 309,
+ 273, 273, 560, 559, 561, 562, 680, 0, 10, 0,
+ 564, 563, 565, 550, 664, 552, 551, 554, 553, 546,
+ 547, 507, 508, 566, 567, 558, 0, 0, 0, 0,
+ 0, 0, 0, 692, 692, 91, 316, 0, 0, 0,
+ 0, 0, 0, 522, 0, 0, 0, 3, 678, 6,
+ 9, 27, 32, 615, 615, 48, 63, 62, 0, 79,
+ 0, 83, 93, 0, 57, 251, 0, 64, 314, 289,
+ 290, 505, 291, 292, 293, 503, 502, 534, 504, 501,
+ 557, 0, 294, 295, 273, 5, 1, 8, 344, 345,
+ 309, 692, 420, 0, 116, 117, 558, 0, 0, 0,
+ 0, 615, 615, 119, 568, 348, 0, 557, 295, 0,
+ 340, 171, 181, 172, 168, 197, 198, 199, 200, 179,
+ 194, 187, 177, 176, 192, 175, 174, 170, 195, 169,
+ 182, 186, 188, 180, 173, 189, 196, 191, 190, 183,
+ 193, 178, 167, 185, 184, 166, 164, 165, 161, 162,
+ 163, 121, 123, 122, 156, 157, 134, 135, 136, 143,
+ 140, 142, 137, 138, 158, 159, 144, 145, 149, 152,
+ 153, 139, 141, 131, 132, 133, 146, 147, 148, 150,
+ 151, 154, 155, 160, 648, 58, 124, 125, 647, 0,
+ 0, 0, 61, 615, 615, 0, 0, 0, 557, 0,
+ 295, 0, 0, 0, 115, 0, 359, 358, 0, 0,
+ 557, 295, 190, 183, 193, 178, 161, 162, 163, 121,
+ 122, 0, 126, 128, 20, 127, 525, 530, 529, 686,
+ 688, 678, 689, 0, 527, 0, 690, 687, 679, 662,
+ 558, 281, 661, 276, 0, 268, 280, 77, 272, 692,
+ 505, 692, 652, 78, 76, 692, 262, 310, 0, 75,
+ 261, 419, 74, 678, 0, 18, 0, 0, 224, 0,
+ 225, 212, 215, 306, 0, 0, 0, 0, 15, 678,
+ 81, 14, 0, 678, 0, 683, 683, 252, 0, 0,
+ 683, 650, 0, 0, 89, 0, 99, 106, 615, 540,
+ 539, 541, 542, 536, 0, 538, 537, 509, 514, 513,
+ 516, 0, 0, 511, 518, 0, 520, 0, 532, 0,
+ 544, 0, 548, 549, 52, 239, 240, 4, 679, 0,
+ 0, 0, 0, 0, 0, 0, 622, 618, 617, 616,
+ 619, 620, 0, 624, 636, 590, 591, 640, 639, 635,
+ 615, 0, 576, 0, 583, 588, 692, 593, 692, 614,
+ 0, 621, 623, 626, 600, 0, 633, 600, 638, 600,
+ 643, 597, 572, 0, 0, 407, 409, 0, 95, 0,
+ 87, 84, 0, 55, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 211, 214, 0, 0, 53, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 675, 692, 674, 0, 677, 676, 0, 424,
+ 422, 315, 506, 0, 0, 413, 68, 313, 337, 116,
+ 117, 118, 548, 549, 576, 569, 335, 0, 692, 0,
+ 0, 0, 673, 672, 59, 0, 692, 306, 0, 0,
+ 350, 0, 349, 0, 0, 692, 0, 0, 0, 0,
+ 0, 0, 306, 0, 692, 0, 332, 0, 129, 0,
+ 0, 526, 528, 0, 0, 691, 656, 657, 282, 660,
+ 275, 0, 680, 269, 0, 278, 0, 270, 0, 678,
+ 0, 678, 692, 692, 263, 274, 678, 0, 312, 51,
+ 681, 0, 0, 0, 0, 0, 0, 17, 678, 304,
+ 13, 0, 80, 300, 303, 307, 685, 253, 684, 685,
+ 255, 308, 651, 105, 97, 0, 92, 0, 0, 692,
+ 0, 615, 317, 404, 600, 543, 0, 0, 517, 523,
+ 510, 512, 519, 521, 533, 545, 0, 0, 7, 21,
+ 22, 23, 24, 25, 49, 50, 580, 628, 581, 579,
+ 0, 678, 678, 600, 0, 0, 582, 645, 595, 646,
+ 592, 645, 596, 577, 599, 607, 629, 599, 610, 637,
+ 599, 612, 642, 641, 0, 0, 692, 281, 28, 30,
+ 0, 31, 678, 0, 85, 96, 47, 33, 45, 0,
+ 256, 201, 29, 0, 295, 0, 229, 234, 235, 236,
+ 231, 233, 243, 244, 237, 238, 210, 213, 241, 242,
+ 0, 221, 680, 230, 232, 226, 227, 228, 216, 217,
+ 218, 219, 220, 665, 670, 666, 671, 418, 273, 416,
+ 0, 692, 665, 667, 666, 668, 417, 273, 665, 666,
+ 273, 692, 692, 34, 256, 202, 44, 209, 66, 69,
+ 0, 0, 0, 116, 117, 120, 0, 0, 692, 0,
+ 678, 0, 298, 692, 692, 493, 0, 0, 692, 351,
+ 669, 305, 0, 665, 666, 692, 353, 322, 352, 325,
+ 669, 305, 0, 665, 666, 0, 0, 0, 0, 0,
+ 280, 0, 328, 655, 658, 654, 279, 284, 283, 277,
+ 692, 659, 653, 260, 258, 264, 265, 267, 311, 682,
+ 19, 0, 26, 208, 82, 16, 678, 683, 98, 90,
+ 102, 104, 0, 101, 103, 680, 0, 599, 535, 0,
+ 524, 222, 223, 622, 620, 367, 678, 360, 575, 573,
+ 599, 40, 247, 342, 0, 0, 589, 692, 644, 0,
+ 598, 627, 600, 600, 600, 634, 600, 622, 600, 42,
+ 249, 343, 395, 393, 0, 392, 391, 288, 0, 94,
+ 88, 0, 0, 0, 0, 0, 692, 0, 457, 458,
+ 459, 491, 476, 456, 0, 0, 0, 475, 490, 0,
+ 56, 0, 436, 449, 451, 461, 440, 460, 462, 442,
+ 484, 444, 453, 455, 454, 54, 0, 0, 0, 415,
+ 72, 421, 265, 0, 0, 414, 70, 410, 65, 0,
+ 0, 692, 338, 0, 0, 421, 341, 649, 60, 494,
+ 495, 692, 496, 0, 692, 356, 0, 0, 354, 0,
+ 0, 421, 0, 0, 0, 0, 0, 421, 0, 130,
+ 531, 0, 327, 0, 0, 285, 271, 678, 692, 11,
+ 301, 254, 100, 0, 397, 0, 0, 318, 515, 368,
+ 365, 625, 0, 678, 0, 0, 594, 578, 599, 603,
+ 599, 605, 599, 611, 599, 608, 613, 0, 0, 390,
+ 680, 680, 585, 586, 692, 692, 375, 0, 631, 375,
+ 375, 373, 0, 284, 286, 86, 46, 257, 665, 666,
+ 0, 665, 666, 487, 478, 491, 465, 472, 0, 466,
+ 469, 0, 480, 0, 481, 483, 474, 489, 488, 463,
+ 437, 438, 445, 0, 0, 0, 0, 0, 0, 0,
+ 39, 206, 38, 207, 73, 0, 36, 204, 37, 205,
+ 71, 411, 412, 0, 0, 0, 0, 570, 336, 0,
+ 0, 498, 357, 0, 12, 500, 0, 319, 0, 320,
+ 0, 0, 333, 0, 0, 0, 283, 692, 259, 266,
+ 403, 0, 0, 0, 0, 0, 363, 574, 41, 248,
+ 600, 600, 600, 600, 43, 250, 0, 0, 0, 584,
+ 645, 371, 372, 375, 383, 630, 0, 386, 0, 388,
+ 408, 287, 421, 486, 464, 0, 0, 479, 0, 446,
+ 0, 450, 452, 441, 447, 477, 485, 443, 246, 245,
+ 35, 203, 425, 423, 0, 0, 0, 497, 0, 107,
+ 114, 0, 499, 0, 323, 326, 0, 0, 0, 692,
+ 427, 428, 426, 401, 680, 399, 402, 406, 405, 369,
+ 366, 0, 361, 604, 599, 601, 606, 609, 396, 394,
+ 306, 0, 587, 692, 0, 374, 381, 375, 375, 375,
+ 632, 375, 375, 473, 467, 470, 482, 439, 0, 67,
+ 339, 113, 0, 692, 0, 692, 692, 0, 0, 0,
+ 0, 429, 0, 0, 398, 0, 364, 0, 600, 669,
+ 305, 370, 0, 378, 0, 380, 0, 387, 0, 384,
+ 389, 0, 0, 448, 110, 112, 0, 665, 666, 492,
+ 355, 334, 692, 692, 430, 329, 400, 362, 602, 375,
+ 375, 375, 375, 468, 471, 108, 0, 0, 0, 0,
+ 0, 379, 0, 376, 382, 385, 0, 330, 331, 0,
+ 0, 0, 375, 692, 0, 0, 377, 431, 0, 0,
+ 692, 692, 433, 435
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -975, -975, -975, 583, -975, 14, -975, -267, 357, -975,
+ -975, 65, -318, -327, -5, -975, -975, 878, -975, 1448,
+ 18, -45, -975, -975, -692, 29, 1098, -224, 4, -38,
+ -298, -482, -19, 1858, -97, 1106, 20, -20, -975, -975,
+ 12, -975, 2730, -975, 780, 73, 24, -384, 83, -975,
+ -9, -454, -269, 17, 118, -379, 26, -975, -975, -975,
+ -975, -975, -975, -975, -975, -975, -975, -975, -975, -975,
+ -975, -975, -975, 141, -151, -468, -14, -590, -975, -975,
+ -975, 324, 497, -975, -637, -975, -975, -256, -975, -18,
+ -975, -975, -975, 271, -975, -975, -975, -80, -975, -479,
+ -975, -569, -975, -975, -975, -599, -975, 70, -276, -975,
+ 159, -975, -975, -914, -729, -975, -975, -975, 317, -882,
+ -738, -975, 15, -975, -975, -975, -975, -975, 276, 62,
+ -159, -975, -975, -975, -975, -975, -302, -975, 885, -975,
+ -975, 421, 1, -975, -975, 679, 1875, 2479, 1141, 1627,
+ -975, -975, -23, 601, 13, 146, 562, 120, -975, -975,
+ -975, -69, 67, -219, -242, -974, -723, -554, -975, 1045,
+ -769, -575, -931, 122, -538, -975, -534, -975, 230, -368,
+ -975, -975, -975, 43, -475, 699, -356, -975, -975, -81,
+ -975, 75, -25, 647, -249, 1060, -268, -21, -1
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ 0, 1, 2, 67, 68, 69, 286, 465, 466, 297,
+ 521, 298, 71, 617, 72, 640, 625, 213, 691, 214,
+ 215, 75, 76, 851, 679, 77, 78, 299, 79, 80,
+ 81, 546, 82, 216, 123, 124, 242, 243, 244, 716,
+ 656, 207, 84, 304, 621, 657, 277, 510, 511, 278,
+ 279, 268, 503, 539, 661, 611, 85, 210, 302, 746,
+ 303, 318, 756, 222, 875, 223, 876, 715, 1076, 682,
+ 680, 986, 460, 289, 471, 707, 867, 1131, 229, 766,
+ 1014, 1105, 1034, 920, 794, 921, 795, 893, 1084, 1085,
+ 552, 897, 606, 396, 87, 88, 672, 447, 671, 494,
+ 1082, 1132, 1178, 1179, 1180, 820, 821, 1053, 822, 823,
+ 824, 825, 948, 949, 826, 827, 828, 953, 829, 830,
+ 831, 832, 694, 861, 990, 994, 89, 90, 91, 332,
+ 333, 557, 92, 93, 94, 558, 252, 253, 254, 489,
+ 95, 96, 97, 326, 98, 99, 218, 219, 102, 220,
+ 456, 681, 371, 372, 373, 374, 375, 923, 924, 376,
+ 377, 378, 780, 595, 380, 381, 382, 383, 580, 384,
+ 385, 386, 928, 929, 387, 388, 389, 390, 391, 588,
+ 209, 461, 309, 513, 272, 129, 686, 659, 464, 459,
+ 438, 517, 894, 518, 537, 256, 257, 258, 301
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule whose
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+static const yytype_int16 yytable[] =
+{
+ 105, 284, 507, 212, 212, 435, 437, 285, 441, 212,
+ 592, 719, 282, 709, 245, 545, 520, 107, 206, 280,
+ 344, 451, 785, 622, 927, 206, 205, 221, 245, 559,
+ 125, 125, 251, 732, 849, 850, 314, 1086, 125, 206,
+ 781, 835, 900, 401, 265, 265, -107, 348, 265, 660,
+ 729, 393, 307, 311, 729, 300, 782, 540, 271, 271,
+ 783, 542, 271, 786, 732, 749, 70, 439, 70, 206,
+ 479, 528, 392, 392, 687, 658, 553, 325, 955, 667,
+ -110, 125, 670, -114, 616, 1056, 950, 394, -112, 255,
+ 895, 702, 961, 276, 281, 446, 306, 310, 267, 273,
+ 712, 951, 274, 688, 864, 1110, 585, 125, 868, -113,
+ 280, -109, 448, 439, 792, 874, 673, 676, 658, 881,
+ 667, 335, 337, 339, 341, 616, 616, 605, 582, 688,
+ -111, 800, 1115, 269, 269, 394, 476, 269, -108, 963,
+ 379, 379, 86, 347, 86, 126, 126, 485, 974, 217,
+ 217, -662, 818, 228, 980, 217, 217, 217, 951, 1086,
+ 217, 793, 367, -99, 293, 752, 1056, -560, 598, 688,
+ 601, 305, 964, 561, 896, 612, 561, 445, 561, 440,
+ 561, 576, 561, 106, 276, 281, 497, 368, 379, 379,
+ 468, 469, 86, 689, 688, 470, 315, -102, 283, -665,
+ -106, 395, 445, 781, 287, -104, 217, -666, 525, 818,
+ 397, 1110, 392, 392, 985, -550, 781, 212, 212, 782,
+ 436, -556, 315, 783, -560, 440, -105, 394, -101, 1057,
+ -550, 275, 782, -559, 550, 432, 783, 1173, 449, -561,
+ 480, 481, 450, -562, 507, 577, 952, -103, 398, 545,
+ -115, -305, -80, 206, -564, -100, 760, 402, 217, 930,
+ 86, 325, 732, -662, 927, -550, -305, 927, 505, -662,
+ 505, -563, -550, -94, 514, 544, 531, 434, 516, 519,
+ 379, 379, 729, 729, 538, 538, 504, 443, 508, 538,
+ -559, 270, 270, 1092, 246, 270, -561, 247, 248, 300,
+ -562, -305, -556, -555, 265, -666, 444, 265, -305, 755,
+ 1116, -564, -555, 478, 860, 545, 1114, 602, 863, 935,
+ 493, 271, 536, -565, 275, 249, 490, 250, -563, 270,
+ 270, -115, -107, 785, 603, -114, 526, -550, -554, 125,
+ 455, -107, -114, 470, 212, 212, 212, 212, 781, 574,
+ 575, 86, 608, -99, 462, 444, -106, 618, 781, 527,
+ 685, 515, 568, 217, 217, -113, 442, 569, 570, 571,
+ 572, 526, 530, 927, 1021, 589, 336, 589, 328, 329,
+ -565, 614, 473, 843, -114, 379, 556, 763, 729, 357,
+ 358, 359, 360, 512, -550, -554, 269, 561, 618, 618,
+ -113, 41, 477, 300, 42, 764, 467, 863, 296, 906,
+ 1002, 463, -109, 70, 1130, 854, 217, 1080, 573, 217,
+ 482, -105, 940, 1174, 217, 217, 125, 957, 86, 486,
+ 330, 331, 514, -101, 844, 86, 86, 379, 872, 873,
+ 488, 998, 246, 86, 958, 247, 248, 665, 58, 658,
+ 665, 667, 843, 844, 315, 493, 690, 514, 520, 493,
+ 718, 886, 265, -111, 502, 695, 506, -109, -111, 502,
+ -108, 665, 522, 249, 514, 250, 296, 726, 899, 781,
+ 419, -109, -111, 514, -103, 616, 535, 265, 665, 86,
+ 217, 217, 217, 217, 86, 217, 217, 665, 891, 1108,
+ 529, 740, 1111, 545, 265, 342, 343, 748, 666, 544,
+ 970, 505, 505, 265, 86, 610, 976, 978, 777, 616,
+ 610, 105, 245, -79, -663, 616, 616, 932, 1081, 736,
+ 737, 1164, 666, 206, 732, 86, 868, 665, 217, 947,
+ 86, 315, 807, 623, 541, 960, 543, 730, 514, 666,
+ 547, 270, 470, 566, 270, 729, 1031, 1032, 666, 567,
+ 975, 975, 665, 909, 911, 913, 578, 915, 520, 916,
+ 884, 125, 584, 125, 217, 544, 1003, 1004, 265, 747,
+ -571, 781, 983, 587, 623, 623, 735, 70, -554, -108,
+ -108, 590, 781, 1176, 1177, 591, 745, 594, 666, 217,
+ 599, 86, 217, -554, 597, 796, 354, 355, 1170, 600,
+ -100, 721, 86, 771, 452, 453, 217, 836, 379, 886,
+ 86, 866, 863, 666, 1197, 217, 520, 798, 1012, 774,
+ 86, 1202, 1203, 789, -432, -434, -663, 604, -554, 125,
+ 678, -421, -663, 419, 523, -554, 615, 775, 1060, 840,
+ 692, 246, 296, 693, 247, 248, 696, 616, 846, 533,
+ 505, 848, 699, 86, 1026, 1027, 280, 1043, 697, 280,
+ 796, 796, 86, 428, 429, 430, 212, 555, 842, 365,
+ 366, 367, 249, 722, 250, 742, 315, 280, 315, 1054,
+ 217, 845, 862, 865, 847, 734, 879, 865, 86, 853,
+ 104, -94, 104, 206, 865, -421, 368, 104, 104, 270,
+ 212, 858, 845, 104, 104, 104, 739, 245, 104, 1065,
+ -421, -348, 454, 454, 925, 217, 538, -109, 206, 505,
+ 1005, 839, 757, 878, 270, 1141, -348, 770, 883, 1156,
+ 276, -111, 773, 276, 791, 217, 802, 508, 801, 803,
+ 104, 270, 841, -421, 315, -421, 296, 431, 618, 839,
+ 270, 276, -421, 544, 104, 855, 856, 981, 688, 1113,
+ 947, -348, 432, 863, 1054, 871, 589, 706, -348, 888,
+ 270, 457, 877, -669, 270, 349, 350, 351, 352, 353,
+ 880, 474, 618, 972, 882, 889, 432, 898, 618, 618,
+ 892, 1093, 1095, 1096, 1097, 514, 432, 433, 902, 904,
+ 576, 610, 270, 908, 434, 270, 104, 778, 104, 665,
+ 910, 778, 217, 86, 912, 270, -109, 125, 698, -109,
+ -109, 458, 914, 917, 943, 265, 705, 944, 434, 1071,
+ -111, 475, 1153, -111, -111, 1073, 717, -669, 434, -558,
+ 796, 956, 959, 966, 968, 962, 217, -109, 965, -109,
+ 991, 212, -669, 995, -558, 246, 520, 936, 247, 248,
+ 967, -111, 993, -111, 988, 947, 1113, 989, 997, 73,
+ 666, 73, 121, 121, 996, 888, 999, 505, 1010, 763,
+ 121, 357, 358, 359, 360, -669, 249, -669, 250, -558,
+ 1015, -665, 1030, 1033, -669, 1009, -558, 764, 1036, 104,
+ 1113, 1038, 246, 483, 759, 247, 248, 1040, 1045, 1168,
+ 969, 104, 104, 589, 589, 1046, 1128, 1129, 432, 73,
+ 618, 1042, 1044, 121, 563, 86, 328, 329, 1047, 922,
+ 1048, 1051, 315, 86, 623, 250, 532, 217, 125, 1049,
+ 534, 354, 355, 125, 334, 1050, 1055, 328, 329, 121,
+ 1062, 1103, -665, 484, 925, 1063, 1088, 925, 1074, 925,
+ 434, 1075, 246, 1087, 104, 247, 248, 104, 623, 217,
+ 1091, 524, 104, 104, 623, 623, 104, 1124, 330, 331,
+ 86, 86, 1094, 104, 104, 1098, 432, 73, 212, 212,
+ 1099, 104, 1100, 249, 86, 250, 865, 217, 1118, 330,
+ 331, 1120, 270, 270, 1119, 125, 86, 86, 1121, 1133,
+ 1161, 1077, 1078, 931, 1135, 86, -665, 1189, 1137, 246,
+ 1142, 475, 247, 248, 1144, 925, 86, 86, 434, 1146,
+ 548, -665, -557, 1198, 1199, 1148, 833, 104, 104, 104,
+ 104, 104, 104, 104, 104, 432, 1165, -557, 1151, 1134,
+ 249, 833, 250, 1029, 1152, -665, 491, -666, 1035, 247,
+ 248, -295, 104, 925, -665, 925, -665, 925, 865, 925,
+ -665, 246, 270, -665, 247, 248, -295, 1175, 73, 1187,
+ 549, -306, -557, 104, 1188, 1190, 104, 434, 104, -557,
+ 1191, 104, 589, 1182, 246, 741, -306, 247, 248, 1186,
+ 226, 130, 1160, 925, 805, 1166, 623, 919, 270, 982,
+ 1117, -295, 514, 1052, 695, 865, 86, 86, -295, 432,
+ 1068, -666, 104, 954, 86, 1011, 665, 250, 492, 833,
+ 1159, -306, 104, 104, 217, 217, 86, 208, -306, 776,
+ 1102, 0, 265, 0, 1101, 1107, 733, 104, 0, 104,
+ 104, 865, 865, 738, 806, 73, 0, 0, 0, 432,
+ 104, 434, 73, 73, 104, 744, 922, 0, 104, 922,
+ 73, 0, 922, 104, 922, 212, 212, 1122, 104, 0,
+ 0, 121, 865, 0, 0, -666, 0, 666, 0, 865,
+ 865, 0, 432, 0, 458, 0, 0, 984, 1194, 1195,
+ -666, 434, 86, 0, 86, 0, 0, 86, 0, 0,
+ 992, 104, 0, 675, 677, 0, 73, 0, 768, 769,
+ 104, 73, 1000, 1001, 0, 0, 833, 1123, 0, 0,
+ 0, 1007, 833, -666, 434, -666, 0, 0, 104, -666,
+ 922, 73, -666, 1013, 0, 0, 104, 675, 677, 799,
+ 778, 0, 0, 931, 217, 0, 931, 0, 931, 86,
+ 86, 0, 73, 0, 0, 472, 0, 73, 121, 0,
+ 73, 472, 0, 104, 0, 270, 0, 0, 922, 0,
+ 922, 0, 922, 787, 922, 357, 358, 359, 360, 327,
+ 328, 329, 0, 104, 834, 562, 743, 0, 328, 329,
+ 0, 361, 338, 328, 329, 340, 328, 329, 495, 834,
+ 0, 73, 73, 246, 0, 0, 247, 248, 922, 0,
+ 86, 217, 217, 0, 931, 0, 363, 857, 73, 86,
+ 86, 0, 1064, 365, 366, 367, 0, 0, 0, 73,
+ 1072, 0, 330, 331, 0, 0, 250, 73, 0, 0,
+ 330, 331, 1079, 554, 833, 330, 331, 73, 330, 331,
+ 368, 0, 931, 0, 931, 0, 931, 0, 931, 0,
+ 104, 104, 0, 0, 0, 833, 833, 0, 0, 0,
+ 555, 328, 329, 890, 560, 328, 329, 834, 0, 270,
+ 73, 564, 328, 329, 565, 328, 329, 0, 495, 73,
+ 0, 0, 931, 901, 104, 583, 0, 808, 809, 810,
+ 0, 0, 579, 121, 0, 121, 1037, 1039, 1125, 0,
+ 1126, 0, 0, 1127, 945, 73, 0, 0, 812, 0,
+ 593, 39, 40, 330, 331, 0, 813, 330, 331, 74,
+ 0, 74, 122, 122, 330, 331, 0, 330, 331, 0,
+ 122, 758, 328, 329, 0, 246, 833, 833, 247, 248,
+ 0, 833, 0, 0, 814, 0, 0, 0, 0, 0,
+ 815, 816, 0, 817, 0, 1162, 1163, 0, 0, 57,
+ 0, 121, 502, 104, 834, 0, 249, 0, 250, 74,
+ 834, 104, 104, 122, 763, 104, 357, 358, 359, 360,
+ 819, 0, 0, 0, 330, 331, 0, 120, 0, 0,
+ 0, 0, 764, 0, 946, 0, 0, 0, 0, 122,
+ 1106, 0, 0, 0, 1008, 0, 104, 104, 0, 833,
+ 708, 708, 104, 104, 0, 0, 1193, 363, 104, 104,
+ 1017, 833, 0, 765, 0, 1200, 1201, 0, 416, 417,
+ 73, 0, 104, 0, 0, 104, 0, 74, 0, 0,
+ 0, 419, 833, 833, 104, 104, 0, 0, 0, 0,
+ 0, 0, 0, 104, 0, -678, -678, -678, 0, -678,
+ -678, 495, -678, 0, 104, 104, 554, -678, 495, 426,
+ 427, 428, 429, 430, 1143, 1145, 1147, 833, 1149, 1150,
+ 0, 763, 0, 357, 358, 359, 360, 971, 973, 0,
+ 0, 0, 834, 977, 979, 767, 0, 0, 103, 764,
+ 103, 128, 128, 763, 0, 357, 358, 359, 360, 231,
+ 0, 0, 784, 834, 834, 788, 0, 0, 0, 971,
+ 973, 764, 977, 979, 363, 0, 0, 0, 74, 1083,
+ 1016, 357, 358, 359, 360, 419, 1181, 1183, 1184, 1185,
+ 0, 0, 73, 0, 104, 0, 363, 764, 103, 121,
+ 73, 73, 317, 0, 104, 104, 0, 246, 0, 1196,
+ 247, 248, 104, 426, 427, 428, 429, 430, 0, 0,
+ 0, 0, 104, 104, 104, 0, 0, 0, 317, 0,
+ 0, -678, 0, 0, 0, 73, 0, -678, 249, 0,
+ 250, 73, 73, 0, 834, 834, 0, 73, 73, 834,
+ 0, 0, 0, 0, 0, 74, 0, 0, 0, 0,
+ 852, 73, 74, 74, 0, 0, 103, 416, 417, 0,
+ 74, 0, 0, 73, 73, 1061, 0, 0, 0, 0,
+ 419, 122, 73, 0, 356, 0, 357, 358, 359, 360,
+ 104, 0, 104, 73, 73, 104, 0, 0, 1061, 0,
+ 0, 472, 361, 0, 0, 423, 424, 425, 426, 427,
+ 428, 429, 430, 0, 0, 0, 74, 834, 0, 0,
+ 121, 74, 0, 0, 0, 121, 0, 363, 0, 834,
+ 0, 0, 0, 364, 365, 366, 367, 0, 0, 0,
+ 0, 74, 104, 0, 0, 0, 0, 104, 104, 0,
+ 834, 834, 0, 0, 0, 0, 0, 103, 926, 907,
+ 0, 368, 74, 0, 369, 0, 0, 74, 122, 0,
+ 74, 0, 0, 73, 0, 0, 0, 551, 0, 83,
+ 0, 83, 0, 73, 73, 834, 0, 121, 0, 0,
+ 227, 73, 0, 0, 0, 0, 100, 0, 100, 127,
+ 127, 127, 0, 73, 0, 0, 0, 230, 104, 104,
+ 104, 74, 74, 0, 0, 0, 0, 104, 104, 0,
+ 0, 0, 416, 417, 0, 0, 0, 0, 74, 83,
+ 0, 0, 0, 987, 103, 419, 0, 0, 0, 74,
+ 0, 103, 103, 0, 0, 0, 100, 74, 0, 103,
+ 316, 0, 0, 0, 403, 0, 0, 74, 708, 0,
+ 317, 472, 425, 426, 427, 428, 429, 430, 0, 73,
+ 0, 73, 0, 1020, 73, 1022, 316, 0, 0, 1023,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 74, 0, 0, 0, 0, 103, 0, 83, 0, 74,
+ 103, 404, 405, 406, 407, 408, 409, 410, 411, 412,
+ 413, 414, 415, 122, 100, 122, 0, 416, 417, 0,
+ 103, 0, 418, 0, 0, 74, 73, 73, 0, 0,
+ 419, 0, 0, 0, 356, 0, 357, 358, 359, 360,
+ 0, 103, 0, 0, 0, 0, 103, 317, 0, 624,
+ 0, 420, 361, 421, 422, 423, 424, 425, 426, 427,
+ 428, 429, 430, 0, 0, 0, 0, 0, 0, 0,
+ 472, 0, 0, 0, 0, 0, 472, 363, 0, 1089,
+ 1090, 122, 0, 364, 365, 366, 367, 73, 83, 0,
+ 624, 624, 0, 0, 0, 0, 73, 73, 808, 809,
+ 810, 1109, 0, 1112, 0, 100, 0, 103, 0, 0,
+ 0, 368, 0, 0, 369, 811, 0, 0, 103, 812,
+ 0, 0, 39, 40, 0, 1104, 103, 813, 0, 0,
+ 0, 0, 0, 0, 0, 0, 103, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 74, 0, 0, 0, 0, 814, 1136, 472, 472, 1138,
+ 0, 815, 816, 0, 817, 83, 818, 0, 0, 103,
+ 57, 0, 83, 83, 0, 0, 0, 0, 103, 0,
+ 83, 0, 100, 0, 0, 0, 0, 0, 0, 100,
+ 100, 819, 317, 0, 317, 0, 0, 100, 120, 0,
+ 0, 0, 1167, 0, 103, 0, 0, 1169, 316, 1171,
+ 0, 0, 0, 1172, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 83, 0, 0, 0,
+ 0, 83, 0, 0, 0, 0, 356, 0, 357, 358,
+ 359, 360, 0, 100, 0, 0, 0, 1192, 100, 0,
+ 0, 83, 0, 0, 361, 0, 0, 0, 472, 0,
+ 317, 0, 74, 0, 0, 0, 0, 0, 100, 122,
+ 74, 74, 83, 0, 472, 472, 0, 83, 0, 363,
+ 619, 0, 0, 0, 0, 364, 365, 366, 367, 100,
+ 0, 0, 0, 0, 100, 316, 356, 0, 357, 358,
+ 359, 360, 0, 0, 0, 74, 0, 0, 0, 0,
+ 0, 74, 74, 368, 361, 0, 369, 74, 74, 0,
+ 0, 619, 619, 0, 0, 0, 0, 0, 362, 103,
+ 0, 74, 0, 0, 0, 0, 0, 0, 83, 363,
+ 0, 0, 0, 74, 74, 364, 365, 366, 367, 83,
+ 0, 0, 74, 0, 0, 100, 0, 83, 808, 809,
+ 810, 0, 0, 74, 74, 0, 100, 83, 0, 0,
+ 0, 0, 0, 368, 100, 945, 369, 0, 0, 812,
+ 0, 0, 39, 40, 100, 0, 0, 813, 0, 370,
+ 122, 0, 0, 0, 0, 122, 0, 0, 0, 0,
+ 83, 0, 0, 0, 0, 0, 0, 0, 0, 83,
+ 0, 0, 0, 0, 0, 814, 0, 100, 0, 0,
+ 0, 815, 816, 0, 817, 0, 100, 0, 0, 0,
+ 57, 0, 0, 0, 0, 83, 0, 0, 0, 0,
+ 316, 103, 316, 74, 0, 0, 0, 0, 317, 103,
+ 624, 819, 100, 74, 74, 0, 0, 122, 120, 0,
+ 0, 74, 0, 0, 808, 809, 810, 0, 0, 0,
+ 0, 0, 0, 74, 0, 0, 0, 0, 0, 0,
+ 0, 945, 0, 0, 624, 812, 0, 0, 39, 40,
+ 624, 624, 0, 813, 0, 0, 103, 103, 0, 0,
+ 101, 0, 101, 0, 0, 0, 0, 0, 316, 0,
+ 103, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 814, 103, 103, 0, 0, 0, 815, 816, 0,
+ 0, 103, 0, 0, 0, 0, 57, 0, 0, 74,
+ 0, 74, 103, 103, 74, 0, 0, 0, 0, 0,
+ 101, 0, 0, 0, 0, 0, 0, 819, 0, 0,
+ 83, 0, 0, 0, 120, 0, 0, 0, 0, 128,
+ 0, 0, 0, 0, 128, 0, 0, 100, 0, 0,
+ 0, 0, 0, 0, 0, 0, -692, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 74, 74, 0, -692,
+ -692, -692, -692, -692, -692, 0, -692, 0, 0, 0,
+ 0, -692, -692, -692, 0, 0, 0, 0, 101, 0,
+ 0, 0, 624, -692, -692, 0, -692, -692, -692, -692,
+ -692, 0, 103, 103, 0, 0, 1070, 0, 0, 0,
+ 103, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 103, 0, 0, 0, 0, 74, 0, 0,
+ 0, 0, 0, 0, 0, 0, 74, 74, 0, 0,
+ 0, 0, 83, 0, 0, 0, -692, 0, 0, 0,
+ 83, 619, 0, 0, 0, 0, 0, 0, 0, 100,
+ 0, -692, 0, 0, 0, 0, 316, 100, 0, 0,
+ 0, -692, 0, 0, -692, -692, 0, 0, 0, 101,
+ 0, 0, 0, 0, 0, 619, 0, 0, 103, 0,
+ 103, 619, 619, 103, -692, -692, 0, 83, 83, 0,
+ 275, -692, -692, -692, -692, 0, 0, 0, 0, 0,
+ 0, 83, 0, 0, 100, 100, 0, 0, 0, 0,
+ 0, 0, 0, 83, 83, 0, 0, 0, 100, 0,
+ 0, 0, 83, 0, 0, 266, 266, 0, 0, 266,
+ 100, 100, 0, 83, 83, 103, 103, 0, 0, 100,
+ 0, 0, 0, 0, 0, 0, 101, 0, 0, 0,
+ 100, 100, 0, 101, 101, 0, 288, 290, 291, 292,
+ 0, 101, 0, 266, 308, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 345, 346, 127, 0, 0,
+ 0, 0, 127, 0, 0, 356, 0, 357, 358, 359,
+ 360, 0, 0, 0, 0, 0, 103, 0, 0, 0,
+ 0, 0, 0, 361, 0, 103, 103, 101, 0, 0,
+ 0, 0, 101, 619, 0, 0, 0, 362, 0, 0,
+ 0, 0, 0, 83, 83, 0, 0, 1067, 363, 0,
+ 0, 83, 101, 0, 364, 365, 366, 367, 0, 0,
+ 100, 100, 0, 83, 1069, 0, 0, 0, 100, 0,
+ 0, 0, 0, 101, 0, -692, 0, 0, 101, 0,
+ 100, 101, 368, 0, 0, 369, 0, 0, 0, 0,
+ 0, 0, 356, 0, 357, 358, 359, 360, 370, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 361, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 101, 101, 0, 0, 581, 0, 0, 83,
+ 0, 83, 0, 0, 83, 363, 0, 0, 0, 101,
+ 0, 364, 365, 366, 367, 804, 100, 0, 100, 0,
+ 101, 100, 0, 0, 0, 0, 0, 0, 101, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 101, 368,
+ 0, 0, 369, 404, 405, 406, 407, 408, 409, 410,
+ 411, 412, 413, 414, 415, 0, 83, 83, 0, 416,
+ 417, 498, 499, 500, 345, 0, 0, 0, 0, 0,
+ 0, 101, 419, 100, 100, 266, 0, 0, 266, 0,
+ 101, 0, 0, 0, 0, 0, 0, 356, 0, 357,
+ 358, 359, 360, 420, 0, 421, 422, 423, 424, 425,
+ 426, 427, 428, 429, 430, 361, 101, 356, 0, 357,
+ 358, 359, 360, -280, 0, 0, 0, 83, 0, 0,
+ 0, 779, 0, 0, 0, 361, 83, 83, 0, 0,
+ 363, 0, 0, 0, 100, 0, 364, 365, 366, 367,
+ 0, 903, 0, 100, 100, 0, 0, 0, 0, 0,
+ 363, 0, 0, 0, 0, 0, 364, 365, 366, 367,
+ 0, 0, 0, 0, 368, 0, 0, 369, 0, 0,
+ 0, 0, 0, 0, 586, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 368, 596, 0, 369, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 609, 0, 0,
+ 0, 0, 620, 0, 626, 627, 628, 629, 630, 631,
+ 632, 633, 634, 635, 636, 637, 638, 639, 0, 641,
+ 642, 643, 644, 645, 646, 647, 648, 649, 650, 651,
+ 652, 101, 0, 266, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 674, 674, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 266, 0,
+ 0, 0, 0, 404, 405, 406, 407, 408, 409, 410,
+ 0, 412, 413, 674, 0, 266, 0, 674, 674, 416,
+ 417, 0, 0, 0, 266, 0, 0, 0, 0, 0,
+ 0, 0, 419, 720, 0, 0, 723, 724, 0, 0,
+ 0, 725, 0, 0, 728, 0, 731, 0, 308, 292,
+ 0, 0, 0, 0, 0, 421, 422, 423, 424, 425,
+ 426, 427, 428, 429, 430, 0, 674, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 728, 0, 0, 308,
+ 0, 0, 0, 101, 0, 0, 0, 0, 0, 266,
+ 0, 101, 101, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 761, 762, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 772, 0, 101, 0, 0, 0,
+ 0, 0, 101, 101, 0, 0, 0, 0, 101, 101,
+ 0, 0, 0, 0, 790, 0, 0, 797, 0, 0,
+ 0, 0, 101, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 101, 101, 0, 0, 0, 0,
+ 0, 0, 0, 101, 0, 0, 0, 0, 0, 0,
+ -420, 0, 0, 0, 101, 101, 0, 0, 0, 0,
+ 0, 0, 0, -420, -420, -420, -420, -420, -420, 0,
+ -420, 0, 0, 0, 0, -420, -420, -420, -420, 0,
+ 0, 0, 0, 0, 0, 0, 0, -420, -420, 0,
+ -420, -420, -420, -420, -420, 0, 0, 0, 0, 0,
+ 0, 0, 0, 859, 0, 0, 772, 790, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -420, -420, -420, -420, -420, -420, -420, -420,
+ -420, -420, -420, -420, 101, 0, 0, 885, -420, -420,
+ -420, 0, 0, -420, 101, 101, 728, 308, 0, -420,
+ 0, -420, 101, 0, 0, -420, 0, 0, 0, 0,
+ 0, 0, 0, 0, 101, -420, 0, 0, -420, -420,
+ 0, 0, -420, 0, -420, -420, -420, -420, -420, -420,
+ -420, -420, -420, -420, 0, 0, 0, 0, -420, -420,
+ -420, -420, -420, 0, 275, -420, -420, -420, -420, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 934, 0,
+ 0, 0, 0, 674, 937, 0, 266, 404, 405, 406,
+ 407, 408, 409, 410, 411, 412, 413, 414, 415, 0,
+ 101, 0, 101, 416, 417, 101, 0, 0, 501, 0,
+ 0, 0, 0, 0, 0, 0, 419, 674, 674, 0,
+ 0, 0, 728, 674, 674, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 420, 0, 421,
+ 422, 423, 424, 425, 426, 427, 428, 429, 430, 674,
+ 674, 0, 674, 674, 0, 0, 0, 101, 101, 0,
+ 0, 0, 0, 1006, 0, 0, 0, 292, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, -693, -693,
+ -693, -693, 408, 409, 1018, 1019, -693, -693, 0, 0,
+ 0, 0, 0, 0, 416, 417, 0, 1024, 1025, 0,
+ 0, 0, 0, 0, 0, 0, 0, 419, 0, 0,
+ 0, 0, 0, 1041, 0, 0, 0, 0, 101, 0,
+ 0, 0, 0, 0, 0, 0, 0, 101, 101, 0,
+ 421, 422, 423, 424, 425, 426, 427, 428, 429, 430,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1058, 1059,
+ 0, 0, 0, 0, 0, 674, 0, 0, 0, 0,
+ -692, 3, 0, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 0, 0, 0, 0, 0, 674, 14,
+ 0, 15, 16, 17, 18, 0, 0, 0, 0, 308,
+ 19, 20, 21, 22, 23, 24, 25, 0, 0, 26,
+ 0, 0, 0, 0, 0, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 0, 39, 40,
+ 41, 0, 0, 42, 0, 0, 43, 44, 0, 45,
+ 46, 47, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 48, 49, 0, 0, 0, 0,
+ 0, 50, 0, 0, 51, 52, 0, 53, 54, 0,
+ 55, 0, 0, 0, 56, 0, 57, 58, 59, 0,
+ 60, 61, 62, -296, 63, -692, 0, 0, -692, -692,
+ 0, 0, 0, 0, 0, 0, -296, -296, -296, -296,
+ -296, -296, 0, -296, 64, 65, 66, 0, -296, 0,
+ -296, -296, -296, 266, 0, 0, -692, 0, -692, 0,
+ -296, -296, 0, -296, -296, -296, -296, -296, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -296, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, -296, -296, -296, -296, -296,
+ -296, -296, -296, -296, -296, -296, -296, 0, 0, 0,
+ 0, -296, -296, -296, 0, 0, -296, 0, 0, 0,
+ 0, 0, -296, 0, -296, 0, 0, 0, -296, 0,
+ 0, 0, 0, 0, 0, 0, -296, 0, -296, 0,
+ 0, -296, -296, 0, 0, -296, -296, -296, -296, -296,
+ -296, -296, -296, -296, -296, -296, -296, 0, 0, -550,
+ 0, 0, -296, -296, -296, -296, 0, 0, -296, -296,
+ -296, -296, -550, -550, -550, -550, -550, -550, 0, -550,
+ 0, 0, 0, 0, -550, 0, -550, -550, 0, 0,
+ 0, 0, 0, 0, 0, 0, -550, -550, 0, -550,
+ -550, -550, -550, -550, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 496, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, -550, -550, -550, -550, -550, -550, -550, -550, -550,
+ -550, -550, -550, 0, 0, 0, 0, -550, -550, -550,
+ 0, -550, -550, 0, 0, 0, 0, 0, -550, 0,
+ -550, 0, 0, 0, -550, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, -550, 0, 0, -550, -550, 0,
+ -550, -550, 0, -550, -550, -550, -550, -550, -550, -550,
+ -550, -550, -550, 0, 0, -692, 0, 0, -550, -550,
+ -550, -550, 0, 0, -550, -550, -550, -550, -692, -692,
+ -692, -692, -692, -692, 0, -692, 0, 0, 0, 0,
+ -692, -692, -692, -692, 0, 0, 0, 0, 0, 0,
+ 0, 0, -692, -692, 0, -692, -692, -692, -692, -692,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, -692, -692, -692,
+ -692, -692, -692, -692, -692, -692, -692, -692, -692, 0,
+ 0, 0, 0, -692, -692, -692, 0, 0, -692, 0,
+ 0, 0, 0, 0, -692, 0, -692, 0, 0, 0,
+ -692, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -692, 0, 0, -692, -692, 0, 0, -692, 0, -692,
+ -692, -692, -692, -692, -692, -692, -692, -692, -692, 0,
+ 0, -692, 0, -692, -692, -692, -692, -692, 0, 275,
+ -692, -692, -692, -692, -692, -692, -692, -692, -692, -692,
+ 0, -692, 0, 0, 0, 0, -692, 0, -692, -692,
+ 0, 0, 0, 0, 0, 0, 0, 0, -692, -692,
+ 0, -692, -692, -692, -692, -692, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, -692, -692, -692, -692, -692, -692, -692,
+ -692, -692, -692, -692, -692, 0, 0, 0, 0, -692,
+ -692, -692, 0, 0, -692, 0, 0, 0, 0, 0,
+ -692, 0, -692, 0, 0, 0, -692, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -692, 0, 0, -692,
+ -692, 0, 0, -692, 0, -692, -692, -692, -692, -692,
+ -692, -692, -692, -692, -692, 0, 0, -669, 0, 0,
+ -692, -692, -692, -692, 0, 275, -692, -692, -692, -692,
+ -669, -669, -669, 0, -669, -669, 0, -669, 0, 0,
+ 0, 0, -669, -669, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, -669, -669, 0, -669, -669, -669,
+ -669, -669, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -669,
+ -669, -669, -669, -669, -669, -669, -669, -669, -669, -669,
+ -669, 0, 0, 0, 0, -669, -669, -669, 0, 837,
+ -669, 0, 0, 0, 0, 0, 0, 0, -669, 0,
+ 0, 0, -669, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -669, 0, 0, -669, -669, 0, -110, -669,
+ 0, -669, -669, -669, -669, -669, -669, -669, -669, -669,
+ -669, 0, 0, -669, 0, -669, -669, -669, 0, -102,
+ 0, 0, -669, -669, -669, -669, -669, -669, -669, 0,
+ -669, -669, 0, -669, 0, 0, 0, 0, -669, -669,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -669, -669, 0, -669, -669, -669, -669, -669, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, -669, -669, -669, -669, -669,
+ -669, -669, -669, -669, -669, -669, -669, 0, 0, 0,
+ 0, -669, -669, -669, 0, 837, -669, 0, 0, 0,
+ 0, 0, 0, 0, -669, 0, 0, 0, -669, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, -669, 0,
+ 0, -669, -669, 0, -110, -669, 0, -669, -669, -669,
+ -669, -669, -669, -669, -669, -669, -669, 0, 0, -305,
+ 0, -669, -669, -669, 0, -669, 0, 0, -669, -669,
+ -669, -669, -305, -305, -305, 0, -305, -305, 0, -305,
+ 0, 0, 0, 0, -305, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -305, -305, 0, -305,
+ -305, -305, -305, -305, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, -305, -305, -305, -305, -305, -305, -305, -305, -305,
+ -305, -305, -305, 0, 0, 0, 0, -305, -305, -305,
+ 0, 838, -305, 0, 0, 0, 0, 0, 0, 0,
+ -305, 0, 0, 0, -305, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, -305, 0, 0, -305, -305, 0,
+ -112, -305, 0, -305, -305, -305, -305, -305, -305, -305,
+ -305, -305, -305, 0, 0, -305, 0, 0, -305, -305,
+ 0, -104, 0, 0, -305, -305, -305, -305, -305, -305,
+ -305, 0, -305, -305, 0, -305, 0, 0, 0, 0,
+ -305, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -305, -305, 0, -305, -305, -305, -305, -305,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, -305, -305, -305,
+ -305, -305, -305, -305, -305, -305, -305, -305, -305, 0,
+ 0, 0, 0, -305, -305, -305, 0, 838, -305, 0,
+ 0, 0, 0, 0, 0, 0, -305, 0, 0, 0,
+ -305, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -305, 0, 0, -305, -305, 0, -112, -305, 0, -305,
+ -305, -305, -305, -305, -305, -305, -305, -305, -305, 0,
+ 0, 0, 0, 0, -305, -305, 0, -305, 0, 0,
+ -305, -305, -305, -305, 294, 0, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, -692, -692, -692, 0,
+ 0, -692, 14, 0, 15, 16, 17, 18, 0, 0,
+ 0, 0, 0, 19, 20, 21, 22, 23, 24, 25,
+ 0, 0, 26, 0, 0, 0, 0, 0, 27, 0,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 0, 39, 40, 41, 0, 0, 42, 0, 0, 43,
+ 44, 0, 45, 46, 47, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 48, 49, 0,
+ 0, 0, 0, 0, 50, 0, 0, 51, 52, 0,
+ 53, 54, 0, 55, 0, 0, 0, 56, 0, 57,
+ 58, 59, 0, 60, 61, 62, 0, 63, -692, 0,
+ 0, -692, -692, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 64, 65, 66,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -692,
+ 294, -692, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 0, 0, -692, 0, -692, -692, 14, 0,
+ 15, 16, 17, 18, 0, 0, 0, 0, 0, 19,
+ 20, 21, 22, 23, 24, 25, 0, 0, 26, 0,
+ 0, 0, 0, 0, 27, 0, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 0, 39, 40, 41,
+ 0, 0, 42, 0, 0, 43, 44, 0, 45, 46,
+ 47, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 48, 49, 0, 0, 0, 0, 0,
+ 50, 0, 0, 51, 52, 0, 53, 54, 0, 55,
+ 0, 0, 0, 56, 0, 57, 58, 59, 0, 60,
+ 61, 62, 0, 63, -692, 0, 0, -692, -692, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 64, 65, 66, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, -692, 294, -692, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 0, 0,
+ -692, 0, 0, -692, 14, -692, 15, 16, 17, 18,
+ 0, 0, 0, 0, 0, 19, 20, 21, 22, 23,
+ 24, 25, 0, 0, 26, 0, 0, 0, 0, 0,
+ 27, 0, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 0, 39, 40, 41, 0, 0, 42, 0,
+ 0, 43, 44, 0, 45, 46, 47, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 48,
+ 49, 0, 0, 0, 0, 0, 50, 0, 0, 51,
+ 52, 0, 53, 54, 0, 55, 0, 0, 0, 56,
+ 0, 57, 58, 59, 0, 60, 61, 62, 0, 63,
+ -692, 0, 0, -692, -692, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 64,
+ 65, 66, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, -692, 294, -692, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 0, 0, -692, 0, 0, -692,
+ 14, 0, 15, 16, 17, 18, -692, 0, 0, 0,
+ 0, 19, 20, 21, 22, 23, 24, 25, 0, 0,
+ 26, 0, 0, 0, 0, 0, 27, 0, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 0, 39,
+ 40, 41, 0, 0, 42, 0, 0, 43, 44, 0,
+ 45, 46, 47, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 48, 49, 0, 0, 0,
+ 0, 0, 50, 0, 0, 51, 52, 0, 53, 54,
+ 0, 55, 0, 0, 0, 56, 0, 57, 58, 59,
+ 0, 60, 61, 62, 0, 63, -692, 0, 0, -692,
+ -692, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 64, 65, 66, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, -692, 294, -692,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 0, 0, -692, 0, 0, -692, 14, 0, 15, 16,
+ 17, 18, 0, 0, 0, 0, 0, 19, 20, 21,
+ 22, 23, 24, 25, 0, 0, 26, 0, 0, 0,
+ 0, 0, 27, 0, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 0, 39, 40, 41, 0, 0,
+ 42, 0, 0, 43, 44, 0, 45, 46, 47, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 48, 49, 0, 0, 0, 0, 0, 50, 0,
+ 0, 51, 52, 0, 53, 54, 0, 55, 0, 0,
+ 0, 56, 0, 57, 58, 59, 0, 60, 61, 62,
+ 0, 63, -692, 0, 0, -692, -692, 3, 0, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 0,
+ 0, 64, 65, 66, 0, 14, 0, 15, 16, 17,
+ 18, 0, 0, -692, 0, -692, 19, 20, 21, 22,
+ 23, 24, 25, 0, 0, 26, 0, 0, 0, 0,
+ 0, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 0, 39, 40, 41, 0, 0, 42,
+ 0, 0, 43, 44, 0, 45, 46, 47, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 48, 49, 0, 0, 0, 0, 0, 50, 0, 0,
+ 51, 52, 0, 53, 54, 0, 55, 0, 0, 0,
+ 56, 0, 57, 58, 59, 0, 60, 61, 62, 0,
+ 63, -692, 0, 0, -692, -692, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 64, 65, 66, 0, 0, -692, 0, 0, 0, 0,
+ 0, 0, -692, 294, -692, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 0, -692, -692, 0, 0,
+ 0, 14, 0, 15, 16, 17, 18, 0, 0, 0,
+ 0, 0, 19, 20, 21, 22, 23, 24, 25, 0,
+ 0, 26, 0, 0, 0, 0, 0, 27, 0, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 0,
+ 39, 40, 41, 0, 0, 42, 0, 0, 43, 44,
+ 0, 45, 46, 47, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 48, 49, 0, 0,
+ 0, 0, 0, 50, 0, 0, 51, 52, 0, 53,
+ 54, 0, 55, 0, 0, 0, 56, 0, 57, 58,
+ 59, 0, 60, 61, 62, 0, 63, -692, 0, 0,
+ -692, -692, 294, 0, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 0, 0, 64, 65, 66, 0,
+ 14, 0, 15, 16, 17, 18, 0, 0, -692, 0,
+ -692, 19, 20, 21, 22, 23, 24, 25, 0, 0,
+ 26, 0, 0, 0, 0, 0, 27, 0, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 0, 39,
+ 40, 41, 0, 0, 42, 0, 0, 43, 44, 0,
+ 45, 46, 47, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 48, 49, 0, 0, 0,
+ 0, 0, 50, 0, 0, 295, 52, 0, 53, 54,
+ 0, 55, 0, 0, 0, 56, 0, 57, 58, 59,
+ 0, 60, 61, 62, 0, 63, -692, 0, 0, -692,
+ -692, -299, 0, -299, -299, -299, -299, -299, -299, -299,
+ -299, -299, -299, 0, 0, 64, 65, 66, 0, -299,
+ 0, -299, -299, -299, -299, 0, -692, -692, 0, -692,
+ -299, -299, -299, -299, -299, -299, -299, 0, 0, -299,
+ 0, 0, 0, 0, 0, -299, 0, -299, -299, -299,
+ -299, -299, -299, -299, -299, -299, -299, 0, -299, -299,
+ -299, 0, 0, -299, 0, 0, -299, -299, 0, -299,
+ -299, -299, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, -299, -299, 0, 0, 0, 0,
+ 0, -299, 0, 0, -299, -299, 0, -299, -299, 0,
+ -299, 0, 0, 0, -299, 0, -299, -299, -299, 0,
+ -299, -299, -299, 0, -299, -299, 0, 0, -299, -299,
+ 294, 0, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 0, 0, -299, -299, -299, 0, 14, 0,
+ 15, 16, 17, 18, 0, -299, -299, 0, -299, 19,
+ 20, 21, 22, 23, 24, 25, 0, 0, 26, 0,
+ 0, 0, 0, 0, 27, 0, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 0, 39, 40, 41,
+ 0, 0, 42, 0, 0, 43, 44, 0, 45, 46,
+ 47, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 48, 49, 0, 0, 0, 0, 0,
+ 50, 0, 0, 51, 52, 0, 53, 54, 0, 55,
+ 0, 0, 0, 56, 0, 57, 58, 59, 0, 60,
+ 61, 62, 0, 63, -692, 0, 0, -692, -692, 294,
+ 0, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 0, 0, 64, 65, 66, 0, 14, 0, 15,
+ 16, 17, 18, 0, -692, -692, 0, -692, 19, 20,
+ 21, 22, 23, 24, 25, 0, 0, 26, 0, 0,
+ 0, 0, 0, 27, 0, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 0, 39, 40, 41, 0,
+ 0, 42, 0, 0, 43, 44, 0, 45, 46, 47,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 48, 49, 0, 0, 0, 0, 0, 50,
+ 0, 0, 51, 52, 0, 53, 54, 0, 55, 0,
+ 0, 0, 56, 0, 57, 58, 59, 0, 60, 61,
+ 62, 0, 63, -692, 0, 0, -692, -692, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 64, 65, 66, 0, 0, -692, 0, 0,
+ 0, 0, 0, 0, -692, 294, -692, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 0, 0, -692,
+ 0, 0, 0, 14, 0, 15, 16, 17, 18, 0,
+ 0, 0, 0, 0, 19, 20, 21, 22, 23, 24,
+ 25, 0, 0, 26, 0, 0, 0, 0, 0, 27,
+ 0, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 0, 39, 40, 41, 0, 0, 42, 0, 0,
+ 43, 44, 0, 45, 46, 47, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 48, 49,
+ 0, 0, 0, 0, 0, 50, 0, 0, 51, 52,
+ 0, 53, 54, 0, 55, 0, 0, 0, 56, 0,
+ 57, 58, 59, 0, 60, 61, 62, 0, 63, -692,
+ 0, 0, -692, -692, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 64, 65,
+ 66, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -692, 0, -692, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, -679, -679, -679, 0, -679, -679, 14,
+ -679, 15, 16, 17, 18, -679, 0, 0, 0, 0,
+ 19, 20, 21, 22, 23, 24, 25, 0, 0, 26,
+ 0, 0, 0, 0, 0, 27, 0, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 0, 39, 40,
+ 41, 0, 0, 42, 0, 0, 43, 44, 0, 45,
+ 46, 47, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 48, 49, 0, 0, 0, 0,
+ 0, 50, 0, 0, 51, 52, 0, 53, 54, 0,
+ 55, 0, 0, 0, 56, 0, 57, 58, 59, 0,
+ 60, 61, 62, 0, 63, 246, 0, 0, 247, 248,
+ 0, 0, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 0, 0, 64, 65, 66, 0, 14, -679,
+ 15, 16, 17, 18, 0, -679, 249, 0, 250, 19,
+ 20, 21, 22, 23, 24, 25, 0, 0, 26, 0,
+ 0, 0, 0, 0, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 0, 39, 40, 41,
+ 0, 0, 42, 0, 0, 43, 44, 0, 45, 46,
+ 47, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 48, 49, 0, 0, 0, 0, 0,
+ 50, 0, 0, 51, 52, 0, 53, 54, 0, 55,
+ 0, 0, 0, 56, 0, 57, 58, 59, 0, 60,
+ 61, 62, 0, 63, 246, 0, 0, 247, 248, 0,
+ 0, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 0, 0, 0, 64, 65, 66, 0, 14, 0, 15,
+ 16, 17, 18, 0, 0, 249, 0, 250, 19, 20,
+ 21, 22, 23, 24, 25, 0, 0, 26, 0, 0,
+ 0, 0, 0, 0, 0, 0, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 0, 39, 40, 41, 0,
+ 0, 42, 0, 0, 43, 44, 0, 45, 46, 47,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 48, 49, 0, 0, 0, 0, 0, 211,
+ 0, 0, 119, 52, 0, 53, 54, 0, 0, 0,
+ 0, 0, 56, 0, 57, 58, 59, 0, 60, 61,
+ 62, 0, 63, 246, 0, 0, 247, 248, 0, 0,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 0,
+ 0, 0, 64, 65, 66, 0, 14, 0, 108, 109,
+ 17, 18, 0, 0, 249, 0, 250, 110, 111, 112,
+ 22, 23, 24, 25, 0, 0, 113, 0, 0, 0,
+ 0, 0, 0, 0, 0, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 0, 39, 40, 41, 0, 0,
+ 42, 0, 0, 43, 44, 0, 45, 46, 47, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 48, 49, 0, 0, 0, 0, 0, 211, 0,
+ 0, 119, 52, 0, 53, 54, 0, 0, 0, 0,
+ 0, 56, 0, 57, 58, 59, 0, 60, 61, 62,
+ 0, 63, 246, 0, 0, 247, 248, 0, 0, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 0, 0,
+ 0, 64, 264, 66, 0, 14, 0, 15, 16, 17,
+ 18, 0, 0, 249, 0, 250, 19, 20, 21, 22,
+ 23, 24, 25, 0, 0, 26, 0, 0, 0, 0,
+ 0, 0, 0, 0, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 0, 39, 40, 41, 0, 0, 42,
+ 0, 0, 43, 44, 0, 45, 46, 47, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 48, 49, 0, 0, 0, 0, 0, 211, 0, 0,
+ 119, 52, 0, 53, 54, 0, 0, 0, 0, 0,
+ 56, 0, 57, 58, 59, 0, 60, 61, 62, 0,
+ 63, 246, 0, 0, 247, 248, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 64, 65, 66, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 250, 131, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 141, 142, 143, 144, 145,
+ 146, 147, 148, 149, 150, 151, 152, 153, 154, 0,
+ 0, 0, 155, 156, 157, 158, 159, 160, 161, 162,
+ 163, 164, 0, 0, 0, 0, 0, 165, 166, 167,
+ 168, 169, 170, 171, 172, 35, 36, 173, 38, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 116, 174, 175, 176, 177, 178, 179, 180, 181,
+ 0, 0, 182, 183, 0, 0, 0, 0, 184, 185,
+ 186, 187, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 188, 189, 190, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 0, 201, 202, 0,
+ 0, 0, 0, 0, 0, 203, 204, -662, -662, -662,
+ -662, -662, -662, -662, -662, -662, 0, 0, 0, 0,
+ 0, 0, 0, -662, 0, -662, -662, -662, -662, 0,
+ -662, 0, 0, 0, -662, -662, -662, -662, -662, -662,
+ -662, 0, 0, -662, 0, 0, 0, 0, 0, 0,
+ 0, 0, -662, -662, -662, -662, -662, -662, -662, -662,
+ -662, 0, -662, -662, -662, 0, 0, -662, 0, 0,
+ -662, -662, 0, -662, -662, -662, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, -662, -662,
+ 0, 0, 0, 0, 0, -662, 0, 0, -662, -662,
+ 0, -662, -662, 0, -662, 0, -662, -662, -662, 0,
+ -662, -662, -662, 0, -662, -662, -662, 0, -662, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, -662, -662,
+ -662, 0, -662, 0, 0, 0, 0, 0, -662, -663,
+ -663, -663, -663, -663, -663, -663, -663, -663, 0, 0,
+ 0, 0, 0, 0, 0, -663, 0, -663, -663, -663,
+ -663, 0, -663, 0, 0, 0, -663, -663, -663, -663,
+ -663, -663, -663, 0, 0, -663, 0, 0, 0, 0,
+ 0, 0, 0, 0, -663, -663, -663, -663, -663, -663,
+ -663, -663, -663, 0, -663, -663, -663, 0, 0, -663,
+ 0, 0, -663, -663, 0, -663, -663, -663, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -663, -663, 0, 0, 0, 0, 0, -663, 0, 0,
+ -663, -663, 0, -663, -663, 0, -663, 0, -663, -663,
+ -663, 0, -663, -663, -663, 0, -663, -663, -663, 0,
+ -663, 0, 0, 0, 0, 0, 0, -665, -665, -665,
+ -665, -665, -665, -665, -665, -665, 0, 0, 0, 0,
+ -663, -663, -663, -665, -663, -665, -665, -665, -665, 0,
+ -663, 0, 0, 0, -665, -665, -665, -665, -665, -665,
+ -665, 0, 0, -665, 0, 0, 0, 0, 0, 0,
+ 0, 0, -665, -665, -665, -665, -665, -665, -665, -665,
+ -665, 0, -665, -665, -665, 0, 0, -665, 0, 0,
+ -665, -665, 0, -665, -665, -665, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, -665, -665,
+ 0, 0, 0, 0, 0, -665, 869, 0, -665, -665,
+ 0, -665, -665, 0, -665, 0, -665, -665, -665, 0,
+ -665, -665, -665, 0, -665, -665, -665, 0, -665, 0,
+ 0, 0, 0, 0, 0, -110, -666, -666, -666, -666,
+ -666, -666, -666, -666, -666, 0, 0, 0, -665, -665,
+ -665, 0, -666, 0, -666, -666, -666, -666, -665, 0,
+ 0, 0, 0, -666, -666, -666, -666, -666, -666, -666,
+ 0, 0, -666, 0, 0, 0, 0, 0, 0, 0,
+ 0, -666, -666, -666, -666, -666, -666, -666, -666, -666,
+ 0, -666, -666, -666, 0, 0, -666, 0, 0, -666,
+ -666, 0, -666, -666, -666, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, -666, -666, 0,
+ 0, 0, 0, 0, -666, 870, 0, -666, -666, 0,
+ -666, -666, 0, -666, 0, -666, -666, -666, 0, -666,
+ -666, -666, 0, -666, -666, -666, 0, -666, 0, 0,
+ 0, 0, 0, 0, -112, -667, -667, -667, -667, -667,
+ -667, -667, -667, -667, 0, 0, 0, -666, -666, -666,
+ 0, -667, 0, -667, -667, -667, -667, -666, 0, 0,
+ 0, 0, -667, -667, -667, -667, -667, -667, -667, 0,
+ 0, -667, 0, 0, 0, 0, 0, 0, 0, 0,
+ -667, -667, -667, -667, -667, -667, -667, -667, -667, 0,
+ -667, -667, -667, 0, 0, -667, 0, 0, -667, -667,
+ 0, -667, -667, -667, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -667, -667, 0, 0,
+ 0, 0, 0, -667, 0, 0, -667, -667, 0, -667,
+ -667, 0, -667, 0, -667, -667, -667, 0, -667, -667,
+ -667, 0, -667, -667, -667, 0, -667, 0, 0, 0,
+ 0, 0, 0, -668, -668, -668, -668, -668, -668, -668,
+ -668, -668, 0, 0, 0, 0, -667, -667, -667, -668,
+ 0, -668, -668, -668, -668, 0, -667, 0, 0, 0,
+ -668, -668, -668, -668, -668, -668, -668, 0, 0, -668,
+ 0, 0, 0, 0, 0, 0, 0, 0, -668, -668,
+ -668, -668, -668, -668, -668, -668, -668, 0, -668, -668,
+ -668, 0, 0, -668, 0, 0, -668, -668, 0, -668,
+ -668, -668, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, -668, -668, 0, 0, 0, 0,
+ 0, -668, 0, 0, -668, -668, 0, -668, -668, 0,
+ -668, 0, -668, -668, -668, 0, -668, -668, -668, 0,
+ -668, -668, -668, 0, -668, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, -668, -668, -668, 0, 0, 0,
+ 0, 0, 0, 0, -668, 131, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 141, 142, 143, 144, 145,
+ 146, 147, 148, 149, 150, 151, 152, 153, 154, 0,
+ 0, 0, 155, 156, 157, 232, 233, 234, 235, 162,
+ 163, 164, 0, 0, 0, 0, 0, 165, 166, 167,
+ 236, 237, 238, 239, 172, 319, 320, 240, 321, 0,
+ 0, 0, 0, 0, 0, 322, 0, 0, 0, 0,
+ 0, 323, 174, 175, 176, 177, 178, 179, 180, 181,
+ 0, 0, 182, 183, 0, 0, 0, 0, 184, 185,
+ 186, 187, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 188, 189, 190, 0, 0, 0, 0, 324,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 0, 201, 202, 0,
+ 0, 0, 0, 0, 0, 203, 131, 132, 133, 134,
+ 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
+ 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
+ 0, 0, 0, 155, 156, 157, 232, 233, 234, 235,
+ 162, 163, 164, 0, 0, 0, 0, 0, 165, 166,
+ 167, 236, 237, 238, 239, 172, 319, 320, 240, 321,
+ 0, 0, 0, 0, 0, 0, 322, 0, 0, 0,
+ 0, 0, 0, 174, 175, 176, 177, 178, 179, 180,
+ 181, 0, 0, 182, 183, 0, 0, 0, 0, 184,
+ 185, 186, 187, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 188, 189, 190, 0, 0, 0, 0,
+ 487, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 191, 192, 193,
+ 194, 195, 196, 197, 198, 199, 200, 0, 201, 202,
+ 0, 0, 0, 0, 0, 0, 203, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+ 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
+ 154, 0, 0, 0, 155, 156, 157, 232, 233, 234,
+ 235, 162, 163, 164, 0, 0, 0, 0, 0, 165,
+ 166, 167, 236, 237, 238, 239, 172, 0, 0, 240,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 174, 175, 176, 177, 178, 179,
+ 180, 181, 0, 0, 182, 183, 0, 0, 0, 0,
+ 184, 185, 186, 187, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 188, 189, 190, 0, 0, 0,
+ 241, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 191, 192,
+ 193, 194, 195, 196, 197, 198, 199, 200, 0, 201,
+ 202, 0, 0, 0, 0, 0, 0, 203, 131, 132,
+ 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
+ 143, 144, 145, 146, 147, 148, 149, 150, 151, 152,
+ 153, 154, 0, 0, 0, 155, 156, 157, 232, 233,
+ 234, 235, 162, 163, 164, 0, 0, 0, 0, 0,
+ 165, 166, 167, 236, 237, 238, 239, 172, 0, 0,
+ 240, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 174, 175, 176, 177, 178,
+ 179, 180, 181, 0, 0, 182, 183, 0, 0, 0,
+ 0, 184, 185, 186, 187, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 188, 189, 190, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199, 200, 0,
+ 201, 202, 0, 0, 0, 0, 0, 0, 203, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 0, 0,
+ 0, 0, 0, 0, 0, 14, 0, 108, 109, 17,
+ 18, 0, 0, 0, 0, 0, 110, 111, 112, 22,
+ 23, 24, 25, 0, 0, 113, 0, 0, 0, 0,
+ 0, 0, 0, 0, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 0, 39, 40, 41, 0, 0, 42,
+ 0, 0, 43, 44, 0, 116, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 312, 0, 0,
+ 119, 52, 0, 53, 54, 0, 0, 0, 0, 0,
+ 56, 0, 57, 58, 59, 0, 60, 61, 62, 0,
+ 63, 0, 0, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 0, 0, 0, 0, 0, 0, 0, 14,
+ 120, 108, 109, 17, 18, 0, 0, 0, 313, 0,
+ 110, 111, 112, 22, 23, 24, 25, 0, 0, 113,
+ 0, 0, 0, 0, 0, 0, 0, 0, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 0, 39, 40,
+ 41, 0, 0, 42, 0, 0, 43, 44, 0, 116,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 312, 0, 0, 119, 52, 0, 53, 54, 0,
+ 0, 0, 0, 0, 56, 0, 57, 58, 59, 0,
+ 60, 61, 62, 0, 63, 0, 0, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 0, 0, 0,
+ 0, 0, 0, 14, 120, 15, 16, 17, 18, 0,
+ 0, 0, 613, 0, 19, 20, 21, 22, 23, 24,
+ 25, 0, 0, 26, 0, 0, 0, 0, 0, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 0, 39, 40, 41, 0, 0, 42, 0, 0,
+ 43, 44, 0, 45, 46, 47, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 48, 49,
+ 0, 0, 0, 0, 0, 50, 0, 0, 51, 52,
+ 0, 53, 54, 0, 55, 0, 0, 0, 56, 0,
+ 57, 58, 59, 0, 60, 61, 62, 0, 63, 0,
+ 0, 0, 0, 0, 0, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 0, 0, 0, 64, 65,
+ 66, 14, 0, 15, 16, 17, 18, 0, 0, 0,
+ 0, 0, 19, 20, 21, 22, 23, 24, 25, 0,
+ 0, 26, 0, 0, 0, 0, 0, 27, 0, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 0,
+ 39, 40, 41, 0, 0, 42, 0, 0, 43, 44,
+ 0, 45, 46, 47, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 48, 49, 0, 0,
+ 0, 0, 0, 50, 0, 0, 51, 52, 0, 53,
+ 54, 0, 55, 0, 0, 0, 56, 0, 57, 58,
+ 59, 0, 60, 61, 62, 0, 63, 0, 0, 0,
+ 0, 0, 0, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 0, 0, 0, 0, 64, 65, 66, 14,
+ 0, 15, 16, 17, 18, 0, 0, 0, 0, 0,
+ 19, 20, 21, 22, 23, 24, 25, 0, 0, 113,
+ 0, 0, 0, 0, 0, 0, 0, 0, 30, 31,
+ 32, 259, 34, 35, 36, 37, 38, 0, 39, 40,
+ 41, 0, 0, 42, 0, 0, 43, 44, 0, 260,
+ 46, 47, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 48, 49, 0, 0, 0, 0,
+ 0, 211, 0, 0, 119, 52, 0, 53, 54, 0,
+ 261, 0, 262, 263, 56, 0, 57, 58, 59, 0,
+ 60, 61, 62, 0, 63, 0, 0, 0, 0, 0,
+ 0, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 0, 0, 0, 0, 64, 264, 66, 14, 0, 15,
+ 16, 17, 18, 0, 0, 0, 0, 0, 19, 20,
+ 21, 22, 23, 24, 25, 0, 0, 113, 0, 0,
+ 0, 0, 0, 0, 0, 0, 30, 31, 32, 259,
+ 34, 35, 36, 37, 38, 0, 39, 40, 41, 0,
+ 0, 42, 0, 0, 43, 44, 0, 260, 46, 47,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 48, 509, 0, 0, 0, 0, 0, 211,
+ 0, 0, 119, 52, 0, 53, 54, 0, 261, 0,
+ 262, 263, 56, 0, 57, 58, 59, 0, 60, 61,
+ 62, 0, 63, 0, 0, 0, 0, 0, 0, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 0, 0,
+ 0, 0, 64, 264, 66, 14, 0, 108, 109, 17,
+ 18, 0, 0, 0, 0, 0, 110, 111, 112, 22,
+ 23, 24, 25, 0, 0, 113, 0, 0, 0, 0,
+ 0, 0, 0, 0, 30, 31, 32, 259, 34, 35,
+ 36, 37, 38, 0, 39, 40, 41, 0, 0, 42,
+ 0, 0, 43, 44, 0, 260, 46, 47, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 48, 49, 0, 0, 0, 0, 0, 211, 0, 0,
+ 119, 52, 0, 53, 54, 0, 727, 0, 262, 263,
+ 56, 0, 57, 58, 59, 0, 60, 61, 62, 0,
+ 63, 0, 0, 0, 0, 0, 0, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 0, 0, 0, 0,
+ 64, 264, 66, 14, 0, 108, 109, 17, 18, 0,
+ 0, 0, 0, 0, 110, 111, 112, 22, 23, 24,
+ 25, 0, 0, 113, 0, 0, 0, 0, 0, 0,
+ 0, 0, 30, 31, 32, 259, 34, 35, 36, 37,
+ 38, 0, 39, 40, 41, 0, 0, 42, 0, 0,
+ 43, 44, 0, 260, 46, 47, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 48, 887,
+ 0, 0, 0, 0, 0, 211, 0, 0, 119, 52,
+ 0, 53, 54, 0, 727, 0, 262, 263, 56, 0,
+ 57, 58, 59, 0, 60, 61, 62, 0, 63, 0,
+ 0, 0, 0, 0, 0, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 0, 0, 0, 0, 64, 264,
+ 66, 14, 0, 108, 109, 17, 18, 0, 0, 0,
+ 0, 0, 110, 111, 112, 22, 23, 24, 25, 0,
+ 0, 113, 0, 0, 0, 0, 0, 0, 0, 0,
+ 30, 31, 32, 259, 34, 35, 36, 37, 38, 0,
+ 39, 40, 41, 0, 0, 42, 0, 0, 43, 44,
+ 0, 260, 46, 47, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 48, 49, 0, 0,
+ 0, 0, 0, 211, 0, 0, 119, 52, 0, 53,
+ 54, 0, 261, 0, 262, 0, 56, 0, 57, 58,
+ 59, 0, 60, 61, 62, 0, 63, 0, 0, 0,
+ 0, 0, 0, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 0, 0, 0, 0, 64, 264, 66, 14,
+ 0, 108, 109, 17, 18, 0, 0, 0, 0, 0,
+ 110, 111, 112, 22, 23, 24, 25, 0, 0, 113,
+ 0, 0, 0, 0, 0, 0, 0, 0, 30, 31,
+ 32, 259, 34, 35, 36, 37, 38, 0, 39, 40,
+ 41, 0, 0, 42, 0, 0, 43, 44, 0, 260,
+ 46, 47, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 48, 49, 0, 0, 0, 0,
+ 0, 211, 0, 0, 119, 52, 0, 53, 54, 0,
+ 0, 0, 262, 263, 56, 0, 57, 58, 59, 0,
+ 60, 61, 62, 0, 63, 0, 0, 0, 0, 0,
+ 0, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 0, 0, 0, 0, 64, 264, 66, 14, 0, 108,
+ 109, 17, 18, 0, 0, 0, 0, 0, 110, 111,
+ 112, 22, 23, 24, 25, 0, 0, 113, 0, 0,
+ 0, 0, 0, 0, 0, 0, 30, 31, 32, 259,
+ 34, 35, 36, 37, 38, 0, 39, 40, 41, 0,
+ 0, 42, 0, 0, 43, 44, 0, 260, 46, 47,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 48, 49, 0, 0, 0, 0, 0, 211,
+ 0, 0, 119, 52, 0, 53, 54, 0, 727, 0,
+ 262, 0, 56, 0, 57, 58, 59, 0, 60, 61,
+ 62, 0, 63, 0, 0, 0, 0, 0, 0, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 0, 0,
+ 0, 0, 64, 264, 66, 14, 0, 108, 109, 17,
+ 18, 0, 0, 0, 0, 0, 110, 111, 112, 22,
+ 23, 24, 25, 0, 0, 113, 0, 0, 0, 0,
+ 0, 0, 0, 0, 30, 31, 32, 259, 34, 35,
+ 36, 37, 38, 0, 39, 40, 41, 0, 0, 42,
+ 0, 0, 43, 44, 0, 260, 46, 47, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 48, 49, 0, 0, 0, 0, 0, 211, 0, 0,
+ 119, 52, 0, 53, 54, 0, 0, 0, 262, 0,
+ 56, 0, 57, 58, 59, 0, 60, 61, 62, 0,
+ 63, 0, 0, 0, 0, 0, 0, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 0, 0, 0, 0,
+ 64, 264, 66, 14, 0, 15, 16, 17, 18, 0,
+ 0, 0, 0, 0, 19, 20, 21, 22, 23, 24,
+ 25, 0, 0, 113, 0, 0, 0, 0, 0, 0,
+ 0, 0, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 0, 39, 40, 41, 0, 0, 42, 0, 0,
+ 43, 44, 0, 45, 46, 47, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 48, 49,
+ 0, 0, 0, 0, 0, 211, 0, 0, 119, 52,
+ 0, 53, 54, 0, 607, 0, 0, 0, 56, 0,
+ 57, 58, 59, 0, 60, 61, 62, 0, 63, 0,
+ 0, 0, 0, 0, 0, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 0, 0, 0, 0, 64, 264,
+ 66, 14, 0, 108, 109, 17, 18, 0, 0, 0,
+ 0, 0, 110, 111, 112, 22, 23, 24, 25, 0,
+ 0, 113, 0, 0, 0, 0, 0, 0, 0, 0,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 0,
+ 39, 40, 41, 0, 0, 42, 0, 0, 43, 44,
+ 0, 45, 46, 47, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 48, 49, 0, 0,
+ 0, 0, 0, 211, 0, 0, 119, 52, 0, 53,
+ 54, 0, 261, 0, 0, 0, 56, 0, 57, 58,
+ 59, 0, 60, 61, 62, 0, 63, 0, 0, 0,
+ 0, 0, 0, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 0, 0, 0, 0, 64, 264, 66, 14,
+ 0, 108, 109, 17, 18, 0, 0, 0, 0, 0,
+ 110, 111, 112, 22, 23, 24, 25, 0, 0, 113,
+ 0, 0, 0, 0, 0, 0, 0, 0, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 0, 39, 40,
+ 41, 0, 0, 42, 0, 0, 43, 44, 0, 45,
+ 46, 47, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 48, 49, 0, 0, 0, 0,
+ 0, 211, 0, 0, 119, 52, 0, 53, 54, 0,
+ 607, 0, 0, 0, 56, 0, 57, 58, 59, 0,
+ 60, 61, 62, 0, 63, 0, 0, 0, 0, 0,
+ 0, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 0, 0, 0, 0, 64, 264, 66, 14, 0, 108,
+ 109, 17, 18, 0, 0, 0, 0, 0, 110, 111,
+ 112, 22, 23, 24, 25, 0, 0, 113, 0, 0,
+ 0, 0, 0, 0, 0, 0, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 0, 39, 40, 41, 0,
+ 0, 42, 0, 0, 43, 44, 0, 45, 46, 47,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 48, 49, 0, 0, 0, 0, 0, 211,
+ 0, 0, 119, 52, 0, 53, 54, 0, 933, 0,
+ 0, 0, 56, 0, 57, 58, 59, 0, 60, 61,
+ 62, 0, 63, 0, 0, 0, 0, 0, 0, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 0, 0,
+ 0, 0, 64, 264, 66, 14, 0, 108, 109, 17,
+ 18, 0, 0, 0, 0, 0, 110, 111, 112, 22,
+ 23, 24, 25, 0, 0, 113, 0, 0, 0, 0,
+ 0, 0, 0, 0, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 0, 39, 40, 41, 0, 0, 42,
+ 0, 0, 43, 44, 0, 45, 46, 47, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 48, 49, 0, 0, 0, 0, 0, 211, 0, 0,
+ 119, 52, 0, 53, 54, 0, 727, 0, 0, 0,
+ 56, 0, 57, 58, 59, 0, 60, 61, 62, 0,
+ 63, 0, 0, 0, 0, 0, 0, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 0, 0, 0, 0,
+ 64, 264, 66, 14, 0, 15, 16, 17, 18, 0,
+ 0, 0, 0, 0, 19, 20, 21, 22, 23, 24,
+ 25, 0, 0, 26, 0, 0, 0, 0, 0, 0,
+ 0, 0, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 0, 39, 40, 41, 0, 0, 42, 0, 0,
+ 43, 44, 0, 45, 46, 47, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 48, 49,
+ 0, 0, 0, 0, 0, 211, 0, 0, 119, 52,
+ 0, 53, 54, 0, 0, 0, 0, 0, 56, 0,
+ 57, 58, 59, 0, 60, 61, 62, 0, 63, 0,
+ 0, 0, 0, 0, 0, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 0, 0, 0, 0, 64, 65,
+ 66, 14, 0, 108, 109, 17, 18, 0, 0, 0,
+ 0, 0, 110, 111, 112, 22, 23, 24, 25, 0,
+ 0, 113, 0, 0, 0, 0, 0, 0, 0, 0,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 0,
+ 39, 40, 41, 0, 0, 42, 0, 0, 43, 44,
+ 0, 45, 46, 47, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 48, 49, 0, 0,
+ 0, 0, 0, 211, 0, 0, 119, 52, 0, 53,
+ 54, 0, 0, 0, 0, 0, 56, 0, 57, 58,
+ 59, 0, 60, 61, 62, 0, 63, 0, 0, 0,
+ 0, 0, 0, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 0, 0, 0, 0, 64, 264, 66, 14,
+ 0, 15, 16, 17, 18, 0, 0, 0, 0, 0,
+ 19, 20, 21, 22, 23, 24, 25, 0, 0, 113,
+ 0, 0, 0, 0, 0, 0, 0, 0, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 0, 39, 40,
+ 41, 0, 0, 42, 0, 0, 43, 44, 0, 45,
+ 46, 47, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 48, 49, 0, 0, 0, 0,
+ 0, 211, 0, 0, 119, 52, 0, 53, 54, 0,
+ 0, 0, 0, 0, 56, 0, 57, 58, 59, 0,
+ 60, 61, 62, 0, 63, 0, 0, 0, 0, 0,
+ 0, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 0, 0, 0, 0, 64, 264, 66, 14, 0, 108,
+ 109, 17, 18, 0, 0, 0, 0, 0, 110, 111,
+ 112, 22, 23, 24, 25, 0, 0, 113, 0, 0,
+ 0, 0, 0, 0, 0, 0, 30, 31, 32, 114,
+ 34, 35, 36, 115, 38, 0, 39, 40, 41, 0,
+ 0, 42, 0, 0, 43, 44, 0, 116, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 117, 0, 0, 118,
+ 0, 0, 119, 52, 0, 53, 54, 0, 0, 0,
+ 0, 0, 56, 0, 57, 58, 59, 0, 60, 61,
+ 62, 0, 63, 0, 0, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 0, 0, 0, 0, 0, 0,
+ 0, 14, 120, 108, 109, 17, 18, 0, 0, 0,
+ 0, 0, 110, 111, 112, 22, 23, 24, 25, 0,
+ 0, 113, 0, 0, 0, 0, 0, 0, 0, 0,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 0,
+ 39, 40, 41, 0, 0, 42, 0, 0, 43, 44,
+ 0, 224, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 225, 0, 0, 51, 52, 0, 53,
+ 54, 0, 55, 0, 0, 0, 56, 0, 57, 58,
+ 59, 0, 60, 61, 62, 0, 63, 0, 0, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 0, 0,
+ 0, 0, 0, 0, 0, 14, 120, 108, 109, 17,
+ 18, 0, 0, 0, 0, 0, 110, 111, 112, 22,
+ 23, 24, 25, 0, 0, 113, 0, 0, 0, 0,
+ 0, 0, 0, 0, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 0, 39, 40, 41, 0, 0, 42,
+ 0, 0, 43, 44, 0, 116, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 312, 0, 0,
+ 399, 52, 0, 53, 54, 0, 400, 0, 0, 0,
+ 56, 0, 57, 58, 59, 0, 60, 61, 62, 0,
+ 63, 0, 0, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 0, 0, 0, 0, 0, 0, 0, 14,
+ 120, 108, 109, 17, 18, 0, 0, 0, 0, 0,
+ 110, 111, 112, 22, 23, 24, 25, 0, 0, 113,
+ 0, 0, 0, 0, 0, 0, 0, 0, 30, 31,
+ 32, 114, 34, 35, 36, 115, 38, 0, 39, 40,
+ 41, 0, 0, 42, 0, 0, 43, 44, 0, 116,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 118, 0, 0, 119, 52, 0, 53, 54, 0,
+ 0, 0, 0, 0, 56, 0, 57, 58, 59, 0,
+ 60, 61, 62, 0, 63, 0, 0, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 0, 0, 0, 0,
+ 0, 0, 0, 14, 120, 108, 109, 17, 18, 0,
+ 0, 0, 0, 0, 110, 111, 112, 22, 23, 24,
+ 25, 0, 0, 113, 0, 0, 0, 0, 0, 0,
+ 0, 0, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 0, 39, 40, 41, 0, 0, 42, 0, 0,
+ 43, 44, 0, 116, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 312, 0, 0, 399, 52,
+ 0, 53, 54, 0, 0, 0, 0, 0, 56, 0,
+ 57, 58, 59, 0, 60, 61, 62, 0, 63, 0,
+ 0, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 0, 0, 0, 0, 0, 0, 0, 14, 120, 108,
+ 109, 17, 18, 0, 0, 0, 0, 0, 110, 111,
+ 112, 22, 23, 24, 25, 0, 0, 113, 0, 0,
+ 0, 0, 0, 0, 0, 0, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 0, 39, 40, 41, 0,
+ 0, 42, 0, 0, 43, 44, 0, 116, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1028,
+ 0, 0, 119, 52, 0, 53, 54, 0, 0, 0,
+ 0, 0, 56, 0, 57, 58, 59, 0, 60, 61,
+ 62, 0, 63, 0, 0, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 0, 0, 0, 0, 0, 0,
+ 0, 14, 120, 108, 109, 17, 18, 0, 0, 0,
+ 0, 0, 110, 111, 112, 22, 23, 24, 25, 0,
+ 0, 113, 0, 0, 0, 0, 0, 0, 0, 0,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 0,
+ 39, 40, 41, 0, 0, 42, 0, 0, 43, 44,
+ 0, 224, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1066, 0, 0, 119, 52, 0, 53,
+ 54, 0, 0, 653, 654, 0, 56, 655, 57, 58,
+ 59, 0, 60, 61, 62, 0, 63, 0, 0, 0,
+ 0, 0, 174, 175, 176, 177, 178, 179, 180, 181,
+ 0, 0, 182, 183, 0, 0, 120, 0, 184, 185,
+ 186, 187, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 188, 189, 190, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 0, 201, 202, 662,
+ 663, 0, 0, 664, 0, 203, 275, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 174, 175,
+ 176, 177, 178, 179, 180, 181, 0, 0, 182, 183,
+ 0, 0, 0, 0, 184, 185, 186, 187, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 188, 189,
+ 190, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 191, 192, 193, 194, 195, 196, 197, 198,
+ 199, 200, 0, 201, 202, 683, 654, 0, 0, 684,
+ 0, 203, 275, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 174, 175, 176, 177, 178, 179,
+ 180, 181, 0, 0, 182, 183, 0, 0, 0, 0,
+ 184, 185, 186, 187, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 188, 189, 190, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 191, 192,
+ 193, 194, 195, 196, 197, 198, 199, 200, 0, 201,
+ 202, 668, 663, 0, 0, 669, 0, 203, 275, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 174, 175, 176, 177, 178, 179, 180, 181, 0, 0,
+ 182, 183, 0, 0, 0, 0, 184, 185, 186, 187,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 188, 189, 190, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 191, 192, 193, 194, 195, 196,
+ 197, 198, 199, 200, 0, 201, 202, 700, 654, 0,
+ 0, 701, 0, 203, 275, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 174, 175, 176, 177,
+ 178, 179, 180, 181, 0, 0, 182, 183, 0, 0,
+ 0, 0, 184, 185, 186, 187, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 188, 189, 190, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
+ 0, 201, 202, 703, 663, 0, 0, 704, 0, 203,
+ 275, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 174, 175, 176, 177, 178, 179, 180, 181,
+ 0, 0, 182, 183, 0, 0, 0, 0, 184, 185,
+ 186, 187, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 188, 189, 190, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 0, 201, 202, 710,
+ 654, 0, 0, 711, 0, 203, 275, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 174, 175,
+ 176, 177, 178, 179, 180, 181, 0, 0, 182, 183,
+ 0, 0, 0, 0, 184, 185, 186, 187, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 188, 189,
+ 190, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 191, 192, 193, 194, 195, 196, 197, 198,
+ 199, 200, 0, 201, 202, 713, 663, 0, 0, 714,
+ 0, 203, 275, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 174, 175, 176, 177, 178, 179,
+ 180, 181, 0, 0, 182, 183, 0, 0, 0, 0,
+ 184, 185, 186, 187, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 188, 189, 190, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 191, 192,
+ 193, 194, 195, 196, 197, 198, 199, 200, 0, 201,
+ 202, 750, 654, 0, 0, 751, 0, 203, 275, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 174, 175, 176, 177, 178, 179, 180, 181, 0, 0,
+ 182, 183, 0, 0, 0, 0, 184, 185, 186, 187,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 188, 189, 190, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 191, 192, 193, 194, 195, 196,
+ 197, 198, 199, 200, 0, 201, 202, 753, 663, 0,
+ 0, 754, 0, 203, 275, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 174, 175, 176, 177,
+ 178, 179, 180, 181, 0, 0, 182, 183, 0, 0,
+ 0, 0, 184, 185, 186, 187, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 188, 189, 190, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
+ 0, 201, 202, 938, 654, 0, 0, 939, 0, 203,
+ 275, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 174, 175, 176, 177, 178, 179, 180, 181,
+ 0, 0, 182, 183, 0, 0, 0, 0, 184, 185,
+ 186, 187, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 188, 189, 190, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 0, 201, 202, 941,
+ 663, 0, 0, 942, 0, 203, 275, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 174, 175,
+ 176, 177, 178, 179, 180, 181, 0, 0, 182, 183,
+ 0, 0, 0, 0, 184, 185, 186, 187, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 188, 189,
+ 190, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 191, 192, 193, 194, 195, 196, 197, 198,
+ 199, 200, 0, 201, 202, 1139, 654, 0, 0, 1140,
+ 0, 203, 275, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 174, 175, 176, 177, 178, 179,
+ 180, 181, 0, 0, 182, 183, 0, 0, 0, 0,
+ 184, 185, 186, 187, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 188, 189, 190, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 191, 192,
+ 193, 194, 195, 196, 197, 198, 199, 200, 0, 201,
+ 202, 1154, 654, 0, 0, 1155, 0, 203, 275, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 174, 175, 176, 177, 178, 179, 180, 181, 0, 0,
+ 182, 183, 0, 0, 0, 0, 184, 185, 186, 187,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 188, 189, 190, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 191, 192, 193, 194, 195, 196,
+ 197, 198, 199, 200, 0, 201, 202, 1157, 663, 0,
+ 0, 1158, 0, 203, 275, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 174, 175, 176, 177,
+ 178, 179, 180, 181, 0, 0, 182, 183, 0, 0,
+ 0, 0, 184, 185, 186, 187, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 188, 189, 190, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
+ 0, 201, 202, 668, 663, 0, 0, 669, 0, 203,
+ 275, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 174, 175, 176, 177, 178, 179, 180, 181,
+ 0, 0, 182, 183, 0, 0, 0, 0, 184, 185,
+ 186, 187, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 188, 189, 190, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 804, 0,
+ 0, 0, 0, 0, 0, 0, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 0, 201, 202, 0,
+ 0, 0, 0, 0, 0, 203, 404, 405, 406, 407,
+ 408, 409, 410, 411, 412, 413, 414, 415, 0, 0,
+ 0, 0, 416, 417, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 419, 0, 0, 0, 0,
+ 905, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 420, 0, 421, 422,
+ 423, 424, 425, 426, 427, 428, 429, 430, 404, 405,
+ 406, 407, 408, 409, 410, 411, 412, 413, 414, 415,
+ 0, 0, 0, 0, 416, 417, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 419, 0, 0,
+ 0, 0, 918, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 420, 0,
+ 421, 422, 423, 424, 425, 426, 427, 428, 429, 430,
+ 404, 405, 406, 407, 408, 409, 410, 411, 412, 413,
+ 414, 415, 0, 0, 0, 0, 416, 417, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 419,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 420, 0, 421, 422, 423, 424, 425, 426, 427, 428,
+ 429, 430, 404, 405, 406, 407, 408, 409, 410, 411,
+ 412, 413, 414, 415, 0, 0, 0, 0, 416, 417,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 419, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 420, 0, 421, 422, 423, 424, 425, 426,
+ 427, 428, 429, 430, 0, 0, 0, 0, 0, 0,
+ 0, 0, -280, 404, 405, 406, 407, 408, 409, 410,
+ 411, 412, 413, 414, 415, 0, 0, 0, 0, 416,
+ 417, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 419, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 420, 0, 421, 422, 423, 424, 425,
+ 426, 427, 428, 429, 430, 0, 0, 0, 0, 0,
+ 0, 0, 0, -282, 404, 405, 406, 407, 408, 409,
+ 410, 411, 412, 413, 414, 415, 0, 0, 0, 0,
+ 416, 417, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 419, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 420, 0, 421, 422, 423, 424,
+ 425, 426, 427, 428, 429, 430, 0, 0, 0, 0,
+ 0, 0, 0, 0, -283, 404, 405, 406, 407, 408,
+ 409, 410, 411, 412, 413, 414, 415, 0, 0, 0,
+ 0, 416, 417, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 419, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 420, 0, 421, 422, 423,
+ 424, 425, 426, 427, 428, 429, 430, 0, 0, 0,
+ 0, 0, 0, 0, 0, -285, 404, 405, 406, 407,
+ 408, 409, 410, 411, 412, 413, 414, 415, 0, 0,
+ 0, 0, 416, 417, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 419, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 420, 0, 421, 422,
+ 423, 424, 425, 426, 427, 428, 429, 430, 404, 405,
+ 406, 407, 408, 409, 410, 411, 412, 413, -693, -693,
+ 0, 0, 0, 0, 416, 417, 404, 405, 406, 407,
+ 408, 409, 0, 0, 412, 413, 0, 419, 0, 0,
+ 0, 0, 416, 417, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 419, 0, 0, 0, 0,
+ 421, 422, 423, 424, 425, 426, 427, 428, 429, 430,
+ 0, 0, 0, 0, 0, 0, 0, 0, 421, 422,
+ 423, 424, 425, 426, 427, 428, 429, 430
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 1, 26, 271, 8, 9, 86, 87, 27, 88, 14,
+ 378, 490, 21, 481, 13, 313, 284, 3, 6, 20,
+ 65, 118, 597, 402, 793, 13, 6, 9, 27, 331,
+ 4, 5, 14, 508, 671, 672, 55, 1011, 12, 27,
+ 594, 640, 765, 81, 15, 16, 25, 68, 19, 433,
+ 504, 74, 53, 54, 508, 51, 594, 306, 15, 16,
+ 594, 310, 19, 597, 539, 547, 1, 26, 3, 57,
+ 221, 295, 73, 74, 458, 431, 318, 57, 816, 435,
+ 25, 55, 438, 25, 402, 967, 815, 74, 25, 14,
+ 29, 475, 821, 20, 21, 104, 53, 54, 15, 16,
+ 484, 51, 19, 459, 694, 1036, 373, 81, 698, 25,
+ 111, 25, 117, 26, 79, 705, 443, 444, 474, 718,
+ 476, 59, 60, 61, 62, 443, 444, 394, 370, 485,
+ 25, 613, 1046, 15, 16, 122, 217, 19, 25, 93,
+ 73, 74, 1, 68, 3, 4, 5, 228, 840, 8,
+ 9, 26, 102, 12, 846, 14, 15, 16, 51, 1133,
+ 19, 126, 103, 142, 55, 549, 1048, 90, 387, 525,
+ 389, 53, 126, 332, 113, 399, 335, 104, 337, 138,
+ 339, 57, 341, 0, 111, 112, 57, 128, 121, 122,
+ 213, 214, 51, 460, 550, 16, 55, 142, 144, 144,
+ 142, 28, 129, 757, 138, 142, 65, 144, 289, 102,
+ 121, 1142, 213, 214, 851, 90, 770, 222, 223, 757,
+ 90, 92, 81, 757, 147, 138, 142, 214, 142, 967,
+ 105, 144, 770, 90, 315, 105, 770, 1151, 51, 90,
+ 222, 223, 55, 90, 513, 121, 139, 142, 142, 547,
+ 121, 90, 121, 241, 90, 142, 558, 121, 117, 793,
+ 119, 241, 737, 138, 1033, 140, 105, 1036, 269, 144,
+ 271, 90, 147, 142, 275, 313, 297, 147, 283, 284,
+ 213, 214, 736, 737, 305, 306, 269, 92, 271, 310,
+ 147, 15, 16, 1016, 115, 19, 147, 118, 119, 295,
+ 147, 140, 92, 92, 275, 144, 92, 278, 147, 551,
+ 1048, 147, 92, 92, 693, 613, 1045, 34, 18, 801,
+ 20, 278, 305, 90, 144, 146, 251, 148, 147, 53,
+ 54, 121, 121, 908, 51, 121, 92, 90, 90, 313,
+ 125, 121, 121, 16, 349, 350, 351, 352, 902, 354,
+ 355, 210, 397, 142, 90, 92, 142, 402, 912, 294,
+ 457, 278, 348, 222, 223, 121, 90, 349, 350, 351,
+ 352, 92, 297, 1142, 908, 376, 62, 378, 64, 65,
+ 147, 400, 121, 92, 121, 318, 324, 51, 842, 53,
+ 54, 55, 56, 275, 147, 147, 278, 556, 443, 444,
+ 121, 60, 92, 399, 63, 69, 55, 18, 51, 777,
+ 878, 147, 121, 348, 25, 682, 275, 1007, 353, 278,
+ 55, 142, 806, 1152, 283, 284, 400, 34, 287, 25,
+ 116, 117, 433, 142, 92, 294, 295, 370, 92, 92,
+ 142, 92, 115, 302, 51, 118, 119, 435, 107, 805,
+ 438, 807, 92, 92, 313, 20, 461, 458, 726, 20,
+ 25, 730, 433, 121, 142, 466, 57, 121, 121, 142,
+ 121, 459, 138, 146, 475, 148, 119, 502, 142, 1033,
+ 101, 121, 121, 484, 142, 803, 141, 458, 476, 348,
+ 349, 350, 351, 352, 353, 354, 355, 485, 747, 1033,
+ 145, 521, 1036, 801, 475, 58, 59, 545, 435, 547,
+ 837, 512, 513, 484, 373, 397, 843, 844, 587, 837,
+ 402, 522, 521, 121, 26, 843, 844, 794, 1007, 512,
+ 513, 1130, 459, 521, 1009, 394, 1126, 525, 397, 815,
+ 399, 400, 623, 402, 139, 821, 55, 504, 549, 476,
+ 142, 275, 16, 101, 278, 1009, 924, 925, 485, 101,
+ 92, 92, 550, 782, 783, 784, 57, 786, 836, 788,
+ 721, 545, 121, 547, 433, 613, 40, 41, 549, 536,
+ 121, 1135, 849, 142, 443, 444, 511, 522, 90, 121,
+ 121, 51, 1146, 1162, 1163, 142, 531, 142, 525, 458,
+ 51, 460, 461, 105, 142, 606, 37, 38, 1142, 142,
+ 142, 493, 471, 584, 58, 59, 475, 642, 551, 888,
+ 479, 17, 18, 550, 1193, 484, 894, 610, 895, 51,
+ 489, 1200, 1201, 604, 40, 41, 138, 121, 140, 613,
+ 99, 26, 144, 101, 287, 147, 142, 69, 975, 658,
+ 15, 115, 295, 13, 118, 119, 121, 975, 667, 302,
+ 661, 670, 16, 522, 920, 921, 667, 943, 121, 670,
+ 671, 672, 531, 131, 132, 133, 681, 63, 661, 101,
+ 102, 103, 146, 15, 148, 139, 545, 688, 547, 965,
+ 549, 667, 693, 694, 670, 145, 716, 698, 557, 681,
+ 1, 142, 3, 691, 705, 90, 128, 8, 9, 433,
+ 715, 691, 688, 14, 15, 16, 145, 716, 19, 986,
+ 105, 90, 121, 122, 793, 584, 747, 16, 716, 730,
+ 881, 658, 142, 715, 458, 1103, 105, 142, 721, 1123,
+ 667, 16, 15, 670, 15, 604, 44, 730, 142, 121,
+ 51, 475, 141, 138, 613, 140, 399, 90, 803, 686,
+ 484, 688, 147, 801, 65, 141, 15, 847, 1124, 1045,
+ 1046, 140, 105, 18, 1050, 141, 777, 27, 147, 736,
+ 504, 90, 141, 26, 508, 40, 41, 42, 43, 44,
+ 139, 90, 837, 838, 15, 139, 105, 139, 843, 844,
+ 141, 1020, 1021, 1022, 1023, 806, 105, 140, 142, 44,
+ 57, 693, 536, 142, 147, 539, 117, 587, 119, 807,
+ 142, 591, 681, 682, 142, 549, 115, 801, 471, 118,
+ 119, 140, 142, 44, 57, 806, 479, 55, 147, 990,
+ 115, 140, 1118, 118, 119, 996, 489, 90, 147, 90,
+ 851, 51, 51, 90, 57, 142, 715, 146, 142, 148,
+ 861, 866, 105, 864, 105, 115, 1134, 802, 118, 119,
+ 142, 146, 14, 148, 15, 1151, 1152, 93, 15, 1,
+ 807, 3, 4, 5, 866, 842, 15, 888, 145, 51,
+ 12, 53, 54, 55, 56, 138, 146, 140, 148, 140,
+ 142, 144, 142, 142, 147, 888, 147, 69, 142, 210,
+ 1186, 142, 115, 90, 557, 118, 119, 15, 142, 1138,
+ 123, 222, 223, 924, 925, 142, 1077, 1078, 105, 51,
+ 975, 141, 141, 55, 62, 794, 64, 65, 139, 793,
+ 142, 51, 801, 802, 803, 148, 299, 806, 922, 142,
+ 303, 37, 38, 927, 61, 142, 55, 64, 65, 81,
+ 15, 1030, 26, 140, 1033, 139, 139, 1036, 15, 1038,
+ 147, 15, 115, 15, 275, 118, 119, 278, 837, 838,
+ 142, 90, 283, 284, 843, 844, 287, 1068, 116, 117,
+ 849, 850, 142, 294, 295, 126, 105, 119, 1003, 1004,
+ 126, 302, 55, 146, 863, 148, 1007, 866, 142, 116,
+ 117, 15, 736, 737, 139, 989, 875, 876, 55, 142,
+ 15, 1003, 1004, 793, 142, 884, 90, 1178, 142, 115,
+ 142, 140, 118, 119, 142, 1104, 895, 896, 147, 142,
+ 90, 105, 90, 1194, 1195, 142, 625, 348, 349, 350,
+ 351, 352, 353, 354, 355, 105, 15, 105, 142, 1084,
+ 146, 640, 148, 922, 142, 144, 115, 144, 927, 118,
+ 119, 90, 373, 1142, 138, 1144, 140, 1146, 1079, 1148,
+ 144, 115, 806, 147, 118, 119, 105, 141, 210, 15,
+ 140, 90, 140, 394, 15, 40, 397, 147, 399, 147,
+ 41, 402, 1103, 142, 115, 522, 105, 118, 119, 142,
+ 12, 5, 1126, 1182, 90, 1133, 975, 793, 842, 848,
+ 1050, 140, 1123, 964, 1125, 1126, 985, 986, 147, 105,
+ 989, 26, 433, 816, 993, 146, 1124, 148, 253, 718,
+ 1125, 140, 443, 444, 1003, 1004, 1005, 6, 147, 587,
+ 1030, -1, 1123, -1, 90, 1033, 509, 458, -1, 460,
+ 461, 1162, 1163, 516, 140, 287, -1, -1, -1, 105,
+ 471, 147, 294, 295, 475, 528, 1030, -1, 479, 1033,
+ 302, -1, 1036, 484, 1038, 1190, 1191, 90, 489, -1,
+ -1, 313, 1193, -1, -1, 90, -1, 1124, -1, 1200,
+ 1201, -1, 105, -1, 140, -1, -1, 850, 1190, 1191,
+ 105, 147, 1071, -1, 1073, -1, -1, 1076, -1, -1,
+ 863, 522, -1, 443, 444, -1, 348, -1, 581, 582,
+ 531, 353, 875, 876, -1, -1, 815, 140, -1, -1,
+ -1, 884, 821, 138, 147, 140, -1, -1, 549, 144,
+ 1104, 373, 147, 896, -1, -1, 557, 477, 478, 612,
+ 1030, -1, -1, 1033, 1123, -1, 1036, -1, 1038, 1128,
+ 1129, -1, 394, -1, -1, 215, -1, 399, 400, -1,
+ 402, 221, -1, 584, -1, 1009, -1, -1, 1142, -1,
+ 1144, -1, 1146, 51, 1148, 53, 54, 55, 56, 63,
+ 64, 65, -1, 604, 625, 61, 526, -1, 64, 65,
+ -1, 69, 63, 64, 65, 63, 64, 65, 258, 640,
+ -1, 443, 444, 115, -1, -1, 118, 119, 1182, -1,
+ 1189, 1190, 1191, -1, 1104, -1, 94, 690, 460, 1198,
+ 1199, -1, 985, 101, 102, 103, -1, -1, -1, 471,
+ 993, -1, 116, 117, -1, -1, 148, 479, -1, -1,
+ 116, 117, 1005, 318, 943, 116, 117, 489, 116, 117,
+ 128, -1, 1142, -1, 1144, -1, 1146, -1, 1148, -1,
+ 681, 682, -1, -1, -1, 964, 965, -1, -1, -1,
+ 63, 64, 65, 746, 63, 64, 65, 718, -1, 1123,
+ 522, 63, 64, 65, 63, 64, 65, -1, 348, 531,
+ -1, -1, 1182, 766, 715, 370, -1, 34, 35, 36,
+ -1, -1, 362, 545, -1, 547, 929, 930, 1071, -1,
+ 1073, -1, -1, 1076, 51, 557, -1, -1, 55, -1,
+ 380, 58, 59, 116, 117, -1, 63, 116, 117, 1,
+ -1, 3, 4, 5, 116, 117, -1, 116, 117, -1,
+ 12, 63, 64, 65, -1, 115, 1045, 1046, 118, 119,
+ -1, 1050, -1, -1, 91, -1, -1, -1, -1, -1,
+ 97, 98, -1, 100, -1, 1128, 1129, -1, -1, 106,
+ -1, 613, 142, 794, 815, -1, 146, -1, 148, 51,
+ 821, 802, 803, 55, 51, 806, 53, 54, 55, 56,
+ 127, -1, -1, -1, 116, 117, -1, 134, -1, -1,
+ -1, -1, 69, -1, 141, -1, -1, -1, -1, 81,
+ 1033, -1, -1, -1, 887, -1, 837, 838, -1, 1118,
+ 480, 481, 843, 844, -1, -1, 1189, 94, 849, 850,
+ 903, 1130, -1, 100, -1, 1198, 1199, -1, 88, 89,
+ 682, -1, 863, -1, -1, 866, -1, 119, -1, -1,
+ -1, 101, 1151, 1152, 875, 876, -1, -1, -1, -1,
+ -1, -1, -1, 884, -1, 13, 14, 15, -1, 17,
+ 18, 531, 20, -1, 895, 896, 551, 25, 538, 129,
+ 130, 131, 132, 133, 1107, 1108, 1109, 1186, 1111, 1112,
+ -1, 51, -1, 53, 54, 55, 56, 837, 838, -1,
+ -1, -1, 943, 843, 844, 580, -1, -1, 1, 69,
+ 3, 4, 5, 51, -1, 53, 54, 55, 56, 12,
+ -1, -1, 597, 964, 965, 600, -1, -1, -1, 869,
+ 870, 69, 872, 873, 94, -1, -1, -1, 210, 51,
+ 100, 53, 54, 55, 56, 101, 1169, 1170, 1171, 1172,
+ -1, -1, 794, -1, 975, -1, 94, 69, 51, 801,
+ 802, 803, 55, -1, 985, 986, -1, 115, -1, 1192,
+ 118, 119, 993, 129, 130, 131, 132, 133, -1, -1,
+ -1, -1, 1003, 1004, 1005, -1, -1, -1, 81, -1,
+ -1, 139, -1, -1, -1, 837, -1, 145, 146, -1,
+ 148, 843, 844, -1, 1045, 1046, -1, 849, 850, 1050,
+ -1, -1, -1, -1, -1, 287, -1, -1, -1, -1,
+ 680, 863, 294, 295, -1, -1, 119, 88, 89, -1,
+ 302, -1, -1, 875, 876, 975, -1, -1, -1, -1,
+ 101, 313, 884, -1, 51, -1, 53, 54, 55, 56,
+ 1071, -1, 1073, 895, 896, 1076, -1, -1, 998, -1,
+ -1, 721, 69, -1, -1, 126, 127, 128, 129, 130,
+ 131, 132, 133, -1, -1, -1, 348, 1118, -1, -1,
+ 922, 353, -1, -1, -1, 927, -1, 94, -1, 1130,
+ -1, -1, -1, 100, 101, 102, 103, -1, -1, -1,
+ -1, 373, 1123, -1, -1, -1, -1, 1128, 1129, -1,
+ 1151, 1152, -1, -1, -1, -1, -1, 210, 793, 779,
+ -1, 128, 394, -1, 131, -1, -1, 399, 400, -1,
+ 402, -1, -1, 975, -1, -1, -1, 144, -1, 1,
+ -1, 3, -1, 985, 986, 1186, -1, 989, -1, -1,
+ 12, 993, -1, -1, -1, -1, 1, -1, 3, 4,
+ 5, 6, -1, 1005, -1, -1, -1, 12, 1189, 1190,
+ 1191, 443, 444, -1, -1, -1, -1, 1198, 1199, -1,
+ -1, -1, 88, 89, -1, -1, -1, -1, 460, 51,
+ -1, -1, -1, 853, 287, 101, -1, -1, -1, 471,
+ -1, 294, 295, -1, -1, -1, 51, 479, -1, 302,
+ 55, -1, -1, -1, 25, -1, -1, 489, 878, -1,
+ 313, 881, 128, 129, 130, 131, 132, 133, -1, 1071,
+ -1, 1073, -1, 908, 1076, 910, 81, -1, -1, 914,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 522, -1, -1, -1, -1, 348, -1, 119, -1, 531,
+ 353, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 545, 119, 547, -1, 88, 89, -1,
+ 373, -1, 93, -1, -1, 557, 1128, 1129, -1, -1,
+ 101, -1, -1, -1, 51, -1, 53, 54, 55, 56,
+ -1, 394, -1, -1, -1, -1, 399, 400, -1, 402,
+ -1, 122, 69, 124, 125, 126, 127, 128, 129, 130,
+ 131, 132, 133, -1, -1, -1, -1, -1, -1, -1,
+ 990, -1, -1, -1, -1, -1, 996, 94, -1, 1014,
+ 1015, 613, -1, 100, 101, 102, 103, 1189, 210, -1,
+ 443, 444, -1, -1, -1, -1, 1198, 1199, 34, 35,
+ 36, 1036, -1, 1038, -1, 210, -1, 460, -1, -1,
+ -1, 128, -1, -1, 131, 51, -1, -1, 471, 55,
+ -1, -1, 58, 59, -1, 142, 479, 63, -1, -1,
+ -1, -1, -1, -1, -1, -1, 489, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 682, -1, -1, -1, -1, 91, 1091, 1077, 1078, 1094,
+ -1, 97, 98, -1, 100, 287, 102, -1, -1, 522,
+ 106, -1, 294, 295, -1, -1, -1, -1, 531, -1,
+ 302, -1, 287, -1, -1, -1, -1, -1, -1, 294,
+ 295, 127, 545, -1, 547, -1, -1, 302, 134, -1,
+ -1, -1, 1137, -1, 557, -1, -1, 1142, 313, 1144,
+ -1, -1, -1, 1148, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 348, -1, -1, -1,
+ -1, 353, -1, -1, -1, -1, 51, -1, 53, 54,
+ 55, 56, -1, 348, -1, -1, -1, 1182, 353, -1,
+ -1, 373, -1, -1, 69, -1, -1, -1, 1178, -1,
+ 613, -1, 794, -1, -1, -1, -1, -1, 373, 801,
+ 802, 803, 394, -1, 1194, 1195, -1, 399, -1, 94,
+ 402, -1, -1, -1, -1, 100, 101, 102, 103, 394,
+ -1, -1, -1, -1, 399, 400, 51, -1, 53, 54,
+ 55, 56, -1, -1, -1, 837, -1, -1, -1, -1,
+ -1, 843, 844, 128, 69, -1, 131, 849, 850, -1,
+ -1, 443, 444, -1, -1, -1, -1, -1, 83, 682,
+ -1, 863, -1, -1, -1, -1, -1, -1, 460, 94,
+ -1, -1, -1, 875, 876, 100, 101, 102, 103, 471,
+ -1, -1, 884, -1, -1, 460, -1, 479, 34, 35,
+ 36, -1, -1, 895, 896, -1, 471, 489, -1, -1,
+ -1, -1, -1, 128, 479, 51, 131, -1, -1, 55,
+ -1, -1, 58, 59, 489, -1, -1, 63, -1, 144,
+ 922, -1, -1, -1, -1, 927, -1, -1, -1, -1,
+ 522, -1, -1, -1, -1, -1, -1, -1, -1, 531,
+ -1, -1, -1, -1, -1, 91, -1, 522, -1, -1,
+ -1, 97, 98, -1, 100, -1, 531, -1, -1, -1,
+ 106, -1, -1, -1, -1, 557, -1, -1, -1, -1,
+ 545, 794, 547, 975, -1, -1, -1, -1, 801, 802,
+ 803, 127, 557, 985, 986, -1, -1, 989, 134, -1,
+ -1, 993, -1, -1, 34, 35, 36, -1, -1, -1,
+ -1, -1, -1, 1005, -1, -1, -1, -1, -1, -1,
+ -1, 51, -1, -1, 837, 55, -1, -1, 58, 59,
+ 843, 844, -1, 63, -1, -1, 849, 850, -1, -1,
+ 1, -1, 3, -1, -1, -1, -1, -1, 613, -1,
+ 863, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 91, 875, 876, -1, -1, -1, 97, 98, -1,
+ -1, 884, -1, -1, -1, -1, 106, -1, -1, 1071,
+ -1, 1073, 895, 896, 1076, -1, -1, -1, -1, -1,
+ 51, -1, -1, -1, -1, -1, -1, 127, -1, -1,
+ 682, -1, -1, -1, 134, -1, -1, -1, -1, 922,
+ -1, -1, -1, -1, 927, -1, -1, 682, -1, -1,
+ -1, -1, -1, -1, -1, -1, 0, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 1128, 1129, -1, 13,
+ 14, 15, 16, 17, 18, -1, 20, -1, -1, -1,
+ -1, 25, 26, 27, -1, -1, -1, -1, 119, -1,
+ -1, -1, 975, 37, 38, -1, 40, 41, 42, 43,
+ 44, -1, 985, 986, -1, -1, 989, -1, -1, -1,
+ 993, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 1005, -1, -1, -1, -1, 1189, -1, -1,
+ -1, -1, -1, -1, -1, -1, 1198, 1199, -1, -1,
+ -1, -1, 794, -1, -1, -1, 90, -1, -1, -1,
+ 802, 803, -1, -1, -1, -1, -1, -1, -1, 794,
+ -1, 105, -1, -1, -1, -1, 801, 802, -1, -1,
+ -1, 115, -1, -1, 118, 119, -1, -1, -1, 210,
+ -1, -1, -1, -1, -1, 837, -1, -1, 1071, -1,
+ 1073, 843, 844, 1076, 138, 139, -1, 849, 850, -1,
+ 144, 145, 146, 147, 148, -1, -1, -1, -1, -1,
+ -1, 863, -1, -1, 849, 850, -1, -1, -1, -1,
+ -1, -1, -1, 875, 876, -1, -1, -1, 863, -1,
+ -1, -1, 884, -1, -1, 15, 16, -1, -1, 19,
+ 875, 876, -1, 895, 896, 1128, 1129, -1, -1, 884,
+ -1, -1, -1, -1, -1, -1, 287, -1, -1, -1,
+ 895, 896, -1, 294, 295, -1, 46, 47, 48, 49,
+ -1, 302, -1, 53, 54, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 65, 66, 922, -1, -1,
+ -1, -1, 927, -1, -1, 51, -1, 53, 54, 55,
+ 56, -1, -1, -1, -1, -1, 1189, -1, -1, -1,
+ -1, -1, -1, 69, -1, 1198, 1199, 348, -1, -1,
+ -1, -1, 353, 975, -1, -1, -1, 83, -1, -1,
+ -1, -1, -1, 985, 986, -1, -1, 989, 94, -1,
+ -1, 993, 373, -1, 100, 101, 102, 103, -1, -1,
+ 985, 986, -1, 1005, 989, -1, -1, -1, 993, -1,
+ -1, -1, -1, 394, -1, 121, -1, -1, 399, -1,
+ 1005, 402, 128, -1, -1, 131, -1, -1, -1, -1,
+ -1, -1, 51, -1, 53, 54, 55, 56, 144, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 69, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 443, 444, -1, -1, 85, -1, -1, 1071,
+ -1, 1073, -1, -1, 1076, 94, -1, -1, -1, 460,
+ -1, 100, 101, 102, 103, 44, 1071, -1, 1073, -1,
+ 471, 1076, -1, -1, -1, -1, -1, -1, 479, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 489, 128,
+ -1, -1, 131, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, -1, 1128, 1129, -1, 88,
+ 89, 261, 262, 263, 264, -1, -1, -1, -1, -1,
+ -1, 522, 101, 1128, 1129, 275, -1, -1, 278, -1,
+ 531, -1, -1, -1, -1, -1, -1, 51, -1, 53,
+ 54, 55, 56, 122, -1, 124, 125, 126, 127, 128,
+ 129, 130, 131, 132, 133, 69, 557, 51, -1, 53,
+ 54, 55, 56, 142, -1, -1, -1, 1189, -1, -1,
+ -1, 85, -1, -1, -1, 69, 1198, 1199, -1, -1,
+ 94, -1, -1, -1, 1189, -1, 100, 101, 102, 103,
+ -1, 85, -1, 1198, 1199, -1, -1, -1, -1, -1,
+ 94, -1, -1, -1, -1, -1, 100, 101, 102, 103,
+ -1, -1, -1, -1, 128, -1, -1, 131, -1, -1,
+ -1, -1, -1, -1, 374, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 128, 385, -1, 131, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 397, -1, -1,
+ -1, -1, 402, -1, 404, 405, 406, 407, 408, 409,
+ 410, 411, 412, 413, 414, 415, 416, 417, -1, 419,
+ 420, 421, 422, 423, 424, 425, 426, 427, 428, 429,
+ 430, 682, -1, 433, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 443, 444, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 458, -1,
+ -1, -1, -1, 72, 73, 74, 75, 76, 77, 78,
+ -1, 80, 81, 473, -1, 475, -1, 477, 478, 88,
+ 89, -1, -1, -1, 484, -1, -1, -1, -1, -1,
+ -1, -1, 101, 493, -1, -1, 496, 497, -1, -1,
+ -1, 501, -1, -1, 504, -1, 506, -1, 508, 509,
+ -1, -1, -1, -1, -1, 124, 125, 126, 127, 128,
+ 129, 130, 131, 132, 133, -1, 526, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 536, -1, -1, 539,
+ -1, -1, -1, 794, -1, -1, -1, -1, -1, 549,
+ -1, 802, 803, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 566, 567, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 584, -1, 837, -1, -1, -1,
+ -1, -1, 843, 844, -1, -1, -1, -1, 849, 850,
+ -1, -1, -1, -1, 604, -1, -1, 607, -1, -1,
+ -1, -1, 863, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 875, 876, -1, -1, -1, -1,
+ -1, -1, -1, 884, -1, -1, -1, -1, -1, -1,
+ 0, -1, -1, -1, 895, 896, -1, -1, -1, -1,
+ -1, -1, -1, 13, 14, 15, 16, 17, 18, -1,
+ 20, -1, -1, -1, -1, 25, 26, 27, 28, -1,
+ -1, -1, -1, -1, -1, -1, -1, 37, 38, -1,
+ 40, 41, 42, 43, 44, -1, -1, -1, -1, -1,
+ -1, -1, -1, 693, -1, -1, 696, 697, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 975, -1, -1, 727, 88, 89,
+ 90, -1, -1, 93, 985, 986, 736, 737, -1, 99,
+ -1, 101, 993, -1, -1, 105, -1, -1, -1, -1,
+ -1, -1, -1, -1, 1005, 115, -1, -1, 118, 119,
+ -1, -1, 122, -1, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 133, -1, -1, -1, -1, 138, 139,
+ 140, 141, 142, -1, 144, 145, 146, 147, 148, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 798, -1,
+ -1, -1, -1, 803, 804, -1, 806, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, -1,
+ 1071, -1, 1073, 88, 89, 1076, -1, -1, 93, -1,
+ -1, -1, -1, -1, -1, -1, 101, 837, 838, -1,
+ -1, -1, 842, 843, 844, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 122, -1, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132, 133, 869,
+ 870, -1, 872, 873, -1, -1, -1, 1128, 1129, -1,
+ -1, -1, -1, 883, -1, -1, -1, 887, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 72, 73,
+ 74, 75, 76, 77, 904, 905, 80, 81, -1, -1,
+ -1, -1, -1, -1, 88, 89, -1, 917, 918, -1,
+ -1, -1, -1, -1, -1, -1, -1, 101, -1, -1,
+ -1, -1, -1, 933, -1, -1, -1, -1, 1189, -1,
+ -1, -1, -1, -1, -1, -1, -1, 1198, 1199, -1,
+ 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
+ -1, -1, -1, -1, -1, -1, -1, -1, 968, 969,
+ -1, -1, -1, -1, -1, 975, -1, -1, -1, -1,
+ 0, 1, -1, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, -1, -1, -1, -1, -1, 998, 19,
+ -1, 21, 22, 23, 24, -1, -1, -1, -1, 1009,
+ 30, 31, 32, 33, 34, 35, 36, -1, -1, 39,
+ -1, -1, -1, -1, -1, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, -1, 58, 59,
+ 60, -1, -1, 63, -1, -1, 66, 67, -1, 69,
+ 70, 71, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 84, 85, -1, -1, -1, -1,
+ -1, 91, -1, -1, 94, 95, -1, 97, 98, -1,
+ 100, -1, -1, -1, 104, -1, 106, 107, 108, -1,
+ 110, 111, 112, 0, 114, 115, -1, -1, 118, 119,
+ -1, -1, -1, -1, -1, -1, 13, 14, 15, 16,
+ 17, 18, -1, 20, 134, 135, 136, -1, 25, -1,
+ 27, 28, 29, 1123, -1, -1, 146, -1, 148, -1,
+ 37, 38, -1, 40, 41, 42, 43, 44, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 57, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, -1, -1, -1,
+ -1, 88, 89, 90, -1, -1, 93, -1, -1, -1,
+ -1, -1, 99, -1, 101, -1, -1, -1, 105, -1,
+ -1, -1, -1, -1, -1, -1, 113, -1, 115, -1,
+ -1, 118, 119, -1, -1, 122, 123, 124, 125, 126,
+ 127, 128, 129, 130, 131, 132, 133, -1, -1, 0,
+ -1, -1, 139, 140, 141, 142, -1, -1, 145, 146,
+ 147, 148, 13, 14, 15, 16, 17, 18, -1, 20,
+ -1, -1, -1, -1, 25, -1, 27, 28, -1, -1,
+ -1, -1, -1, -1, -1, -1, 37, 38, -1, 40,
+ 41, 42, 43, 44, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 57, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, -1, -1, -1, -1, 88, 89, 90,
+ -1, 92, 93, -1, -1, -1, -1, -1, 99, -1,
+ 101, -1, -1, -1, 105, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 115, -1, -1, 118, 119, -1,
+ 121, 122, -1, 124, 125, 126, 127, 128, 129, 130,
+ 131, 132, 133, -1, -1, 0, -1, -1, 139, 140,
+ 141, 142, -1, -1, 145, 146, 147, 148, 13, 14,
+ 15, 16, 17, 18, -1, 20, -1, -1, -1, -1,
+ 25, 26, 27, 28, -1, -1, -1, -1, -1, -1,
+ -1, -1, 37, 38, -1, 40, 41, 42, 43, 44,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, -1,
+ -1, -1, -1, 88, 89, 90, -1, -1, 93, -1,
+ -1, -1, -1, -1, 99, -1, 101, -1, -1, -1,
+ 105, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 115, -1, -1, 118, 119, -1, -1, 122, -1, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132, 133, -1,
+ -1, 0, -1, 138, 139, 140, 141, 142, -1, 144,
+ 145, 146, 147, 148, 13, 14, 15, 16, 17, 18,
+ -1, 20, -1, -1, -1, -1, 25, -1, 27, 28,
+ -1, -1, -1, -1, -1, -1, -1, -1, 37, 38,
+ -1, 40, 41, 42, 43, 44, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, -1, -1, -1, -1, 88,
+ 89, 90, -1, -1, 93, -1, -1, -1, -1, -1,
+ 99, -1, 101, -1, -1, -1, 105, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 115, -1, -1, 118,
+ 119, -1, -1, 122, -1, 124, 125, 126, 127, 128,
+ 129, 130, 131, 132, 133, -1, -1, 0, -1, -1,
+ 139, 140, 141, 142, -1, 144, 145, 146, 147, 148,
+ 13, 14, 15, -1, 17, 18, -1, 20, -1, -1,
+ -1, -1, 25, 26, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 37, 38, -1, 40, 41, 42,
+ 43, 44, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, -1, -1, -1, -1, 88, 89, 90, -1, 92,
+ 93, -1, -1, -1, -1, -1, -1, -1, 101, -1,
+ -1, -1, 105, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 115, -1, -1, 118, 119, -1, 121, 122,
+ -1, 124, 125, 126, 127, 128, 129, 130, 131, 132,
+ 133, -1, -1, 0, -1, 138, 139, 140, -1, 142,
+ -1, -1, 145, 146, 147, 148, 13, 14, 15, -1,
+ 17, 18, -1, 20, -1, -1, -1, -1, 25, 26,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 37, 38, -1, 40, 41, 42, 43, 44, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, -1, -1, -1,
+ -1, 88, 89, 90, -1, 92, 93, -1, -1, -1,
+ -1, -1, -1, -1, 101, -1, -1, -1, 105, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 115, -1,
+ -1, 118, 119, -1, 121, 122, -1, 124, 125, 126,
+ 127, 128, 129, 130, 131, 132, 133, -1, -1, 0,
+ -1, 138, 139, 140, -1, 142, -1, -1, 145, 146,
+ 147, 148, 13, 14, 15, -1, 17, 18, -1, 20,
+ -1, -1, -1, -1, 25, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 37, 38, -1, 40,
+ 41, 42, 43, 44, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, -1, -1, -1, -1, 88, 89, 90,
+ -1, 92, 93, -1, -1, -1, -1, -1, -1, -1,
+ 101, -1, -1, -1, 105, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 115, -1, -1, 118, 119, -1,
+ 121, 122, -1, 124, 125, 126, 127, 128, 129, 130,
+ 131, 132, 133, -1, -1, 0, -1, -1, 139, 140,
+ -1, 142, -1, -1, 145, 146, 147, 148, 13, 14,
+ 15, -1, 17, 18, -1, 20, -1, -1, -1, -1,
+ 25, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 37, 38, -1, 40, 41, 42, 43, 44,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, -1,
+ -1, -1, -1, 88, 89, 90, -1, 92, 93, -1,
+ -1, -1, -1, -1, -1, -1, 101, -1, -1, -1,
+ 105, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 115, -1, -1, 118, 119, -1, 121, 122, -1, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132, 133, -1,
+ -1, -1, -1, -1, 139, 140, -1, 142, -1, -1,
+ 145, 146, 147, 148, 1, -1, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, -1,
+ -1, 18, 19, -1, 21, 22, 23, 24, -1, -1,
+ -1, -1, -1, 30, 31, 32, 33, 34, 35, 36,
+ -1, -1, 39, -1, -1, -1, -1, -1, 45, -1,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ -1, 58, 59, 60, -1, -1, 63, -1, -1, 66,
+ 67, -1, 69, 70, 71, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 84, 85, -1,
+ -1, -1, -1, -1, 91, -1, -1, 94, 95, -1,
+ 97, 98, -1, 100, -1, -1, -1, 104, -1, 106,
+ 107, 108, -1, 110, 111, 112, -1, 114, 115, -1,
+ -1, 118, 119, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 134, 135, 136,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 146,
+ 1, 148, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, -1, -1, 15, -1, 17, 18, 19, -1,
+ 21, 22, 23, 24, -1, -1, -1, -1, -1, 30,
+ 31, 32, 33, 34, 35, 36, -1, -1, 39, -1,
+ -1, -1, -1, -1, 45, -1, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, -1, 58, 59, 60,
+ -1, -1, 63, -1, -1, 66, 67, -1, 69, 70,
+ 71, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 84, 85, -1, -1, -1, -1, -1,
+ 91, -1, -1, 94, 95, -1, 97, 98, -1, 100,
+ -1, -1, -1, 104, -1, 106, 107, 108, -1, 110,
+ 111, 112, -1, 114, 115, -1, -1, 118, 119, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 134, 135, 136, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 146, 1, 148, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, -1, -1,
+ 15, -1, -1, 18, 19, 20, 21, 22, 23, 24,
+ -1, -1, -1, -1, -1, 30, 31, 32, 33, 34,
+ 35, 36, -1, -1, 39, -1, -1, -1, -1, -1,
+ 45, -1, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, -1, 58, 59, 60, -1, -1, 63, -1,
+ -1, 66, 67, -1, 69, 70, 71, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 84,
+ 85, -1, -1, -1, -1, -1, 91, -1, -1, 94,
+ 95, -1, 97, 98, -1, 100, -1, -1, -1, 104,
+ -1, 106, 107, 108, -1, 110, 111, 112, -1, 114,
+ 115, -1, -1, 118, 119, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 134,
+ 135, 136, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 146, 1, 148, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, -1, -1, 15, -1, -1, 18,
+ 19, -1, 21, 22, 23, 24, 25, -1, -1, -1,
+ -1, 30, 31, 32, 33, 34, 35, 36, -1, -1,
+ 39, -1, -1, -1, -1, -1, 45, -1, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56, -1, 58,
+ 59, 60, -1, -1, 63, -1, -1, 66, 67, -1,
+ 69, 70, 71, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 84, 85, -1, -1, -1,
+ -1, -1, 91, -1, -1, 94, 95, -1, 97, 98,
+ -1, 100, -1, -1, -1, 104, -1, 106, 107, 108,
+ -1, 110, 111, 112, -1, 114, 115, -1, -1, 118,
+ 119, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 134, 135, 136, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 146, 1, 148,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ -1, -1, 15, -1, -1, 18, 19, -1, 21, 22,
+ 23, 24, -1, -1, -1, -1, -1, 30, 31, 32,
+ 33, 34, 35, 36, -1, -1, 39, -1, -1, -1,
+ -1, -1, 45, -1, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56, -1, 58, 59, 60, -1, -1,
+ 63, -1, -1, 66, 67, -1, 69, 70, 71, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 84, 85, -1, -1, -1, -1, -1, 91, -1,
+ -1, 94, 95, -1, 97, 98, -1, 100, -1, -1,
+ -1, 104, -1, 106, 107, 108, -1, 110, 111, 112,
+ -1, 114, 115, -1, -1, 118, 119, 1, -1, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, -1,
+ -1, 134, 135, 136, -1, 19, -1, 21, 22, 23,
+ 24, -1, -1, 146, -1, 148, 30, 31, 32, 33,
+ 34, 35, 36, -1, -1, 39, -1, -1, -1, -1,
+ -1, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, -1, 58, 59, 60, -1, -1, 63,
+ -1, -1, 66, 67, -1, 69, 70, 71, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 84, 85, -1, -1, -1, -1, -1, 91, -1, -1,
+ 94, 95, -1, 97, 98, -1, 100, -1, -1, -1,
+ 104, -1, 106, 107, 108, -1, 110, 111, 112, -1,
+ 114, 115, -1, -1, 118, 119, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 134, 135, 136, -1, -1, 139, -1, -1, -1, -1,
+ -1, -1, 146, 1, 148, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, -1, 14, 15, -1, -1,
+ -1, 19, -1, 21, 22, 23, 24, -1, -1, -1,
+ -1, -1, 30, 31, 32, 33, 34, 35, 36, -1,
+ -1, 39, -1, -1, -1, -1, -1, 45, -1, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, -1,
+ 58, 59, 60, -1, -1, 63, -1, -1, 66, 67,
+ -1, 69, 70, 71, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 84, 85, -1, -1,
+ -1, -1, -1, 91, -1, -1, 94, 95, -1, 97,
+ 98, -1, 100, -1, -1, -1, 104, -1, 106, 107,
+ 108, -1, 110, 111, 112, -1, 114, 115, -1, -1,
+ 118, 119, 1, -1, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, -1, -1, 134, 135, 136, -1,
+ 19, -1, 21, 22, 23, 24, -1, -1, 146, -1,
+ 148, 30, 31, 32, 33, 34, 35, 36, -1, -1,
+ 39, -1, -1, -1, -1, -1, 45, -1, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56, -1, 58,
+ 59, 60, -1, -1, 63, -1, -1, 66, 67, -1,
+ 69, 70, 71, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 84, 85, -1, -1, -1,
+ -1, -1, 91, -1, -1, 94, 95, -1, 97, 98,
+ -1, 100, -1, -1, -1, 104, -1, 106, 107, 108,
+ -1, 110, 111, 112, -1, 114, 115, -1, -1, 118,
+ 119, 1, -1, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, -1, -1, 134, 135, 136, -1, 19,
+ -1, 21, 22, 23, 24, -1, 145, 146, -1, 148,
+ 30, 31, 32, 33, 34, 35, 36, -1, -1, 39,
+ -1, -1, -1, -1, -1, 45, -1, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, -1, 58, 59,
+ 60, -1, -1, 63, -1, -1, 66, 67, -1, 69,
+ 70, 71, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 84, 85, -1, -1, -1, -1,
+ -1, 91, -1, -1, 94, 95, -1, 97, 98, -1,
+ 100, -1, -1, -1, 104, -1, 106, 107, 108, -1,
+ 110, 111, 112, -1, 114, 115, -1, -1, 118, 119,
+ 1, -1, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, -1, -1, 134, 135, 136, -1, 19, -1,
+ 21, 22, 23, 24, -1, 145, 146, -1, 148, 30,
+ 31, 32, 33, 34, 35, 36, -1, -1, 39, -1,
+ -1, -1, -1, -1, 45, -1, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, -1, 58, 59, 60,
+ -1, -1, 63, -1, -1, 66, 67, -1, 69, 70,
+ 71, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 84, 85, -1, -1, -1, -1, -1,
+ 91, -1, -1, 94, 95, -1, 97, 98, -1, 100,
+ -1, -1, -1, 104, -1, 106, 107, 108, -1, 110,
+ 111, 112, -1, 114, 115, -1, -1, 118, 119, 1,
+ -1, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, -1, -1, 134, 135, 136, -1, 19, -1, 21,
+ 22, 23, 24, -1, 145, 146, -1, 148, 30, 31,
+ 32, 33, 34, 35, 36, -1, -1, 39, -1, -1,
+ -1, -1, -1, 45, -1, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, -1, 58, 59, 60, -1,
+ -1, 63, -1, -1, 66, 67, -1, 69, 70, 71,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 84, 85, -1, -1, -1, -1, -1, 91,
+ -1, -1, 94, 95, -1, 97, 98, -1, 100, -1,
+ -1, -1, 104, -1, 106, 107, 108, -1, 110, 111,
+ 112, -1, 114, 115, -1, -1, 118, 119, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 134, 135, 136, -1, -1, 139, -1, -1,
+ -1, -1, -1, -1, 146, 1, 148, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, -1, -1, 15,
+ -1, -1, -1, 19, -1, 21, 22, 23, 24, -1,
+ -1, -1, -1, -1, 30, 31, 32, 33, 34, 35,
+ 36, -1, -1, 39, -1, -1, -1, -1, -1, 45,
+ -1, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, -1, 58, 59, 60, -1, -1, 63, -1, -1,
+ 66, 67, -1, 69, 70, 71, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 84, 85,
+ -1, -1, -1, -1, -1, 91, -1, -1, 94, 95,
+ -1, 97, 98, -1, 100, -1, -1, -1, 104, -1,
+ 106, 107, 108, -1, 110, 111, 112, -1, 114, 115,
+ -1, -1, 118, 119, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 134, 135,
+ 136, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 146, -1, 148, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, -1, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, -1, -1, -1, -1,
+ 30, 31, 32, 33, 34, 35, 36, -1, -1, 39,
+ -1, -1, -1, -1, -1, 45, -1, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, -1, 58, 59,
+ 60, -1, -1, 63, -1, -1, 66, 67, -1, 69,
+ 70, 71, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 84, 85, -1, -1, -1, -1,
+ -1, 91, -1, -1, 94, 95, -1, 97, 98, -1,
+ 100, -1, -1, -1, 104, -1, 106, 107, 108, -1,
+ 110, 111, 112, -1, 114, 115, -1, -1, 118, 119,
+ -1, -1, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, -1, -1, 134, 135, 136, -1, 19, 139,
+ 21, 22, 23, 24, -1, 145, 146, -1, 148, 30,
+ 31, 32, 33, 34, 35, 36, -1, -1, 39, -1,
+ -1, -1, -1, -1, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, -1, 58, 59, 60,
+ -1, -1, 63, -1, -1, 66, 67, -1, 69, 70,
+ 71, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 84, 85, -1, -1, -1, -1, -1,
+ 91, -1, -1, 94, 95, -1, 97, 98, -1, 100,
+ -1, -1, -1, 104, -1, 106, 107, 108, -1, 110,
+ 111, 112, -1, 114, 115, -1, -1, 118, 119, -1,
+ -1, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ -1, -1, -1, 134, 135, 136, -1, 19, -1, 21,
+ 22, 23, 24, -1, -1, 146, -1, 148, 30, 31,
+ 32, 33, 34, 35, 36, -1, -1, 39, -1, -1,
+ -1, -1, -1, -1, -1, -1, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, -1, 58, 59, 60, -1,
+ -1, 63, -1, -1, 66, 67, -1, 69, 70, 71,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 84, 85, -1, -1, -1, -1, -1, 91,
+ -1, -1, 94, 95, -1, 97, 98, -1, -1, -1,
+ -1, -1, 104, -1, 106, 107, 108, -1, 110, 111,
+ 112, -1, 114, 115, -1, -1, 118, 119, -1, -1,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, -1,
+ -1, -1, 134, 135, 136, -1, 19, -1, 21, 22,
+ 23, 24, -1, -1, 146, -1, 148, 30, 31, 32,
+ 33, 34, 35, 36, -1, -1, 39, -1, -1, -1,
+ -1, -1, -1, -1, -1, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56, -1, 58, 59, 60, -1, -1,
+ 63, -1, -1, 66, 67, -1, 69, 70, 71, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 84, 85, -1, -1, -1, -1, -1, 91, -1,
+ -1, 94, 95, -1, 97, 98, -1, -1, -1, -1,
+ -1, 104, -1, 106, 107, 108, -1, 110, 111, 112,
+ -1, 114, 115, -1, -1, 118, 119, -1, -1, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, -1, -1,
+ -1, 134, 135, 136, -1, 19, -1, 21, 22, 23,
+ 24, -1, -1, 146, -1, 148, 30, 31, 32, 33,
+ 34, 35, 36, -1, -1, 39, -1, -1, -1, -1,
+ -1, -1, -1, -1, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, -1, 58, 59, 60, -1, -1, 63,
+ -1, -1, 66, 67, -1, 69, 70, 71, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 84, 85, -1, -1, -1, -1, -1, 91, -1, -1,
+ 94, 95, -1, 97, 98, -1, -1, -1, -1, -1,
+ 104, -1, 106, 107, 108, -1, 110, 111, 112, -1,
+ 114, 115, -1, -1, 118, 119, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 134, 135, 136, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 148, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, -1,
+ -1, -1, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, -1, -1, -1, -1, -1, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 69, 70, 71, 72, 73, 74, 75, 76, 77,
+ -1, -1, 80, 81, -1, -1, -1, -1, 86, 87,
+ 88, 89, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 100, 101, 102, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, -1, 135, 136, -1,
+ -1, -1, -1, -1, -1, 143, 144, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, -1, -1, -1, -1,
+ -1, -1, -1, 19, -1, 21, 22, 23, 24, -1,
+ 26, -1, -1, -1, 30, 31, 32, 33, 34, 35,
+ 36, -1, -1, 39, -1, -1, -1, -1, -1, -1,
+ -1, -1, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, -1, 58, 59, 60, -1, -1, 63, -1, -1,
+ 66, 67, -1, 69, 70, 71, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 84, 85,
+ -1, -1, -1, -1, -1, 91, -1, -1, 94, 95,
+ -1, 97, 98, -1, 100, -1, 102, 103, 104, -1,
+ 106, 107, 108, -1, 110, 111, 112, -1, 114, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 134, 135,
+ 136, -1, 138, -1, -1, -1, -1, -1, 144, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, -1, -1,
+ -1, -1, -1, -1, -1, 19, -1, 21, 22, 23,
+ 24, -1, 26, -1, -1, -1, 30, 31, 32, 33,
+ 34, 35, 36, -1, -1, 39, -1, -1, -1, -1,
+ -1, -1, -1, -1, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, -1, 58, 59, 60, -1, -1, 63,
+ -1, -1, 66, 67, -1, 69, 70, 71, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 84, 85, -1, -1, -1, -1, -1, 91, -1, -1,
+ 94, 95, -1, 97, 98, -1, 100, -1, 102, 103,
+ 104, -1, 106, 107, 108, -1, 110, 111, 112, -1,
+ 114, -1, -1, -1, -1, -1, -1, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, -1, -1, -1, -1,
+ 134, 135, 136, 19, 138, 21, 22, 23, 24, -1,
+ 144, -1, -1, -1, 30, 31, 32, 33, 34, 35,
+ 36, -1, -1, 39, -1, -1, -1, -1, -1, -1,
+ -1, -1, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, -1, 58, 59, 60, -1, -1, 63, -1, -1,
+ 66, 67, -1, 69, 70, 71, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 84, 85,
+ -1, -1, -1, -1, -1, 91, 92, -1, 94, 95,
+ -1, 97, 98, -1, 100, -1, 102, 103, 104, -1,
+ 106, 107, 108, -1, 110, 111, 112, -1, 114, -1,
+ -1, -1, -1, -1, -1, 121, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, -1, -1, -1, 134, 135,
+ 136, -1, 19, -1, 21, 22, 23, 24, 144, -1,
+ -1, -1, -1, 30, 31, 32, 33, 34, 35, 36,
+ -1, -1, 39, -1, -1, -1, -1, -1, -1, -1,
+ -1, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ -1, 58, 59, 60, -1, -1, 63, -1, -1, 66,
+ 67, -1, 69, 70, 71, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 84, 85, -1,
+ -1, -1, -1, -1, 91, 92, -1, 94, 95, -1,
+ 97, 98, -1, 100, -1, 102, 103, 104, -1, 106,
+ 107, 108, -1, 110, 111, 112, -1, 114, -1, -1,
+ -1, -1, -1, -1, 121, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, -1, -1, -1, 134, 135, 136,
+ -1, 19, -1, 21, 22, 23, 24, 144, -1, -1,
+ -1, -1, 30, 31, 32, 33, 34, 35, 36, -1,
+ -1, 39, -1, -1, -1, -1, -1, -1, -1, -1,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, -1,
+ 58, 59, 60, -1, -1, 63, -1, -1, 66, 67,
+ -1, 69, 70, 71, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 84, 85, -1, -1,
+ -1, -1, -1, 91, -1, -1, 94, 95, -1, 97,
+ 98, -1, 100, -1, 102, 103, 104, -1, 106, 107,
+ 108, -1, 110, 111, 112, -1, 114, -1, -1, -1,
+ -1, -1, -1, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, -1, -1, -1, -1, 134, 135, 136, 19,
+ -1, 21, 22, 23, 24, -1, 144, -1, -1, -1,
+ 30, 31, 32, 33, 34, 35, 36, -1, -1, 39,
+ -1, -1, -1, -1, -1, -1, -1, -1, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, -1, 58, 59,
+ 60, -1, -1, 63, -1, -1, 66, 67, -1, 69,
+ 70, 71, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 84, 85, -1, -1, -1, -1,
+ -1, 91, -1, -1, 94, 95, -1, 97, 98, -1,
+ 100, -1, 102, 103, 104, -1, 106, 107, 108, -1,
+ 110, 111, 112, -1, 114, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 134, 135, 136, -1, -1, -1,
+ -1, -1, -1, -1, 144, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, -1,
+ -1, -1, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, -1, -1, -1, -1, -1, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, -1,
+ -1, -1, -1, -1, -1, 63, -1, -1, -1, -1,
+ -1, 69, 70, 71, 72, 73, 74, 75, 76, 77,
+ -1, -1, 80, 81, -1, -1, -1, -1, 86, 87,
+ 88, 89, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 100, 101, 102, -1, -1, -1, -1, 107,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, -1, 135, 136, -1,
+ -1, -1, -1, -1, -1, 143, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ -1, -1, -1, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, -1, -1, -1, -1, -1, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ -1, -1, -1, -1, -1, -1, 63, -1, -1, -1,
+ -1, -1, -1, 70, 71, 72, 73, 74, 75, 76,
+ 77, -1, -1, 80, 81, -1, -1, -1, -1, 86,
+ 87, 88, 89, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 100, 101, 102, -1, -1, -1, -1,
+ 107, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 124, 125, 126,
+ 127, 128, 129, 130, 131, 132, 133, -1, 135, 136,
+ -1, -1, -1, -1, -1, -1, 143, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, -1, -1, -1, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, -1, -1, -1, -1, -1, 45,
+ 46, 47, 48, 49, 50, 51, 52, -1, -1, 55,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 70, 71, 72, 73, 74, 75,
+ 76, 77, -1, -1, 80, 81, -1, -1, -1, -1,
+ 86, 87, 88, 89, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 100, 101, 102, -1, -1, -1,
+ 106, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 124, 125,
+ 126, 127, 128, 129, 130, 131, 132, 133, -1, 135,
+ 136, -1, -1, -1, -1, -1, -1, 143, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, -1, -1, -1, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, -1, -1, -1, -1, -1,
+ 45, 46, 47, 48, 49, 50, 51, 52, -1, -1,
+ 55, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 70, 71, 72, 73, 74,
+ 75, 76, 77, -1, -1, 80, 81, -1, -1, -1,
+ -1, 86, 87, 88, 89, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 100, 101, 102, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132, 133, -1,
+ 135, 136, -1, -1, -1, -1, -1, -1, 143, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, -1, -1,
+ -1, -1, -1, -1, -1, 19, -1, 21, 22, 23,
+ 24, -1, -1, -1, -1, -1, 30, 31, 32, 33,
+ 34, 35, 36, -1, -1, 39, -1, -1, -1, -1,
+ -1, -1, -1, -1, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, -1, 58, 59, 60, -1, -1, 63,
+ -1, -1, 66, 67, -1, 69, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 91, -1, -1,
+ 94, 95, -1, 97, 98, -1, -1, -1, -1, -1,
+ 104, -1, 106, 107, 108, -1, 110, 111, 112, -1,
+ 114, -1, -1, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, -1, -1, -1, -1, -1, -1, -1, 19,
+ 134, 21, 22, 23, 24, -1, -1, -1, 142, -1,
+ 30, 31, 32, 33, 34, 35, 36, -1, -1, 39,
+ -1, -1, -1, -1, -1, -1, -1, -1, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, -1, 58, 59,
+ 60, -1, -1, 63, -1, -1, 66, 67, -1, 69,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 91, -1, -1, 94, 95, -1, 97, 98, -1,
+ -1, -1, -1, -1, 104, -1, 106, 107, 108, -1,
+ 110, 111, 112, -1, 114, -1, -1, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, -1, -1, -1,
+ -1, -1, -1, 19, 134, 21, 22, 23, 24, -1,
+ -1, -1, 142, -1, 30, 31, 32, 33, 34, 35,
+ 36, -1, -1, 39, -1, -1, -1, -1, -1, 45,
+ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, -1, 58, 59, 60, -1, -1, 63, -1, -1,
+ 66, 67, -1, 69, 70, 71, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 84, 85,
+ -1, -1, -1, -1, -1, 91, -1, -1, 94, 95,
+ -1, 97, 98, -1, 100, -1, -1, -1, 104, -1,
+ 106, 107, 108, -1, 110, 111, 112, -1, 114, -1,
+ -1, -1, -1, -1, -1, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, -1, -1, -1, 134, 135,
+ 136, 19, -1, 21, 22, 23, 24, -1, -1, -1,
+ -1, -1, 30, 31, 32, 33, 34, 35, 36, -1,
+ -1, 39, -1, -1, -1, -1, -1, 45, -1, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, -1,
+ 58, 59, 60, -1, -1, 63, -1, -1, 66, 67,
+ -1, 69, 70, 71, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 84, 85, -1, -1,
+ -1, -1, -1, 91, -1, -1, 94, 95, -1, 97,
+ 98, -1, 100, -1, -1, -1, 104, -1, 106, 107,
+ 108, -1, 110, 111, 112, -1, 114, -1, -1, -1,
+ -1, -1, -1, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, -1, -1, -1, -1, 134, 135, 136, 19,
+ -1, 21, 22, 23, 24, -1, -1, -1, -1, -1,
+ 30, 31, 32, 33, 34, 35, 36, -1, -1, 39,
+ -1, -1, -1, -1, -1, -1, -1, -1, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, -1, 58, 59,
+ 60, -1, -1, 63, -1, -1, 66, 67, -1, 69,
+ 70, 71, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 84, 85, -1, -1, -1, -1,
+ -1, 91, -1, -1, 94, 95, -1, 97, 98, -1,
+ 100, -1, 102, 103, 104, -1, 106, 107, 108, -1,
+ 110, 111, 112, -1, 114, -1, -1, -1, -1, -1,
+ -1, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ -1, -1, -1, -1, 134, 135, 136, 19, -1, 21,
+ 22, 23, 24, -1, -1, -1, -1, -1, 30, 31,
+ 32, 33, 34, 35, 36, -1, -1, 39, -1, -1,
+ -1, -1, -1, -1, -1, -1, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, -1, 58, 59, 60, -1,
+ -1, 63, -1, -1, 66, 67, -1, 69, 70, 71,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 84, 85, -1, -1, -1, -1, -1, 91,
+ -1, -1, 94, 95, -1, 97, 98, -1, 100, -1,
+ 102, 103, 104, -1, 106, 107, 108, -1, 110, 111,
+ 112, -1, 114, -1, -1, -1, -1, -1, -1, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, -1, -1,
+ -1, -1, 134, 135, 136, 19, -1, 21, 22, 23,
+ 24, -1, -1, -1, -1, -1, 30, 31, 32, 33,
+ 34, 35, 36, -1, -1, 39, -1, -1, -1, -1,
+ -1, -1, -1, -1, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, -1, 58, 59, 60, -1, -1, 63,
+ -1, -1, 66, 67, -1, 69, 70, 71, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 84, 85, -1, -1, -1, -1, -1, 91, -1, -1,
+ 94, 95, -1, 97, 98, -1, 100, -1, 102, 103,
+ 104, -1, 106, 107, 108, -1, 110, 111, 112, -1,
+ 114, -1, -1, -1, -1, -1, -1, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, -1, -1, -1, -1,
+ 134, 135, 136, 19, -1, 21, 22, 23, 24, -1,
+ -1, -1, -1, -1, 30, 31, 32, 33, 34, 35,
+ 36, -1, -1, 39, -1, -1, -1, -1, -1, -1,
+ -1, -1, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, -1, 58, 59, 60, -1, -1, 63, -1, -1,
+ 66, 67, -1, 69, 70, 71, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 84, 85,
+ -1, -1, -1, -1, -1, 91, -1, -1, 94, 95,
+ -1, 97, 98, -1, 100, -1, 102, 103, 104, -1,
+ 106, 107, 108, -1, 110, 111, 112, -1, 114, -1,
+ -1, -1, -1, -1, -1, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, -1, -1, -1, -1, 134, 135,
+ 136, 19, -1, 21, 22, 23, 24, -1, -1, -1,
+ -1, -1, 30, 31, 32, 33, 34, 35, 36, -1,
+ -1, 39, -1, -1, -1, -1, -1, -1, -1, -1,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, -1,
+ 58, 59, 60, -1, -1, 63, -1, -1, 66, 67,
+ -1, 69, 70, 71, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 84, 85, -1, -1,
+ -1, -1, -1, 91, -1, -1, 94, 95, -1, 97,
+ 98, -1, 100, -1, 102, -1, 104, -1, 106, 107,
+ 108, -1, 110, 111, 112, -1, 114, -1, -1, -1,
+ -1, -1, -1, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, -1, -1, -1, -1, 134, 135, 136, 19,
+ -1, 21, 22, 23, 24, -1, -1, -1, -1, -1,
+ 30, 31, 32, 33, 34, 35, 36, -1, -1, 39,
+ -1, -1, -1, -1, -1, -1, -1, -1, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, -1, 58, 59,
+ 60, -1, -1, 63, -1, -1, 66, 67, -1, 69,
+ 70, 71, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 84, 85, -1, -1, -1, -1,
+ -1, 91, -1, -1, 94, 95, -1, 97, 98, -1,
+ -1, -1, 102, 103, 104, -1, 106, 107, 108, -1,
+ 110, 111, 112, -1, 114, -1, -1, -1, -1, -1,
+ -1, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ -1, -1, -1, -1, 134, 135, 136, 19, -1, 21,
+ 22, 23, 24, -1, -1, -1, -1, -1, 30, 31,
+ 32, 33, 34, 35, 36, -1, -1, 39, -1, -1,
+ -1, -1, -1, -1, -1, -1, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, -1, 58, 59, 60, -1,
+ -1, 63, -1, -1, 66, 67, -1, 69, 70, 71,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 84, 85, -1, -1, -1, -1, -1, 91,
+ -1, -1, 94, 95, -1, 97, 98, -1, 100, -1,
+ 102, -1, 104, -1, 106, 107, 108, -1, 110, 111,
+ 112, -1, 114, -1, -1, -1, -1, -1, -1, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, -1, -1,
+ -1, -1, 134, 135, 136, 19, -1, 21, 22, 23,
+ 24, -1, -1, -1, -1, -1, 30, 31, 32, 33,
+ 34, 35, 36, -1, -1, 39, -1, -1, -1, -1,
+ -1, -1, -1, -1, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, -1, 58, 59, 60, -1, -1, 63,
+ -1, -1, 66, 67, -1, 69, 70, 71, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 84, 85, -1, -1, -1, -1, -1, 91, -1, -1,
+ 94, 95, -1, 97, 98, -1, -1, -1, 102, -1,
+ 104, -1, 106, 107, 108, -1, 110, 111, 112, -1,
+ 114, -1, -1, -1, -1, -1, -1, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, -1, -1, -1, -1,
+ 134, 135, 136, 19, -1, 21, 22, 23, 24, -1,
+ -1, -1, -1, -1, 30, 31, 32, 33, 34, 35,
+ 36, -1, -1, 39, -1, -1, -1, -1, -1, -1,
+ -1, -1, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, -1, 58, 59, 60, -1, -1, 63, -1, -1,
+ 66, 67, -1, 69, 70, 71, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 84, 85,
+ -1, -1, -1, -1, -1, 91, -1, -1, 94, 95,
+ -1, 97, 98, -1, 100, -1, -1, -1, 104, -1,
+ 106, 107, 108, -1, 110, 111, 112, -1, 114, -1,
+ -1, -1, -1, -1, -1, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, -1, -1, -1, -1, 134, 135,
+ 136, 19, -1, 21, 22, 23, 24, -1, -1, -1,
+ -1, -1, 30, 31, 32, 33, 34, 35, 36, -1,
+ -1, 39, -1, -1, -1, -1, -1, -1, -1, -1,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, -1,
+ 58, 59, 60, -1, -1, 63, -1, -1, 66, 67,
+ -1, 69, 70, 71, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 84, 85, -1, -1,
+ -1, -1, -1, 91, -1, -1, 94, 95, -1, 97,
+ 98, -1, 100, -1, -1, -1, 104, -1, 106, 107,
+ 108, -1, 110, 111, 112, -1, 114, -1, -1, -1,
+ -1, -1, -1, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, -1, -1, -1, -1, 134, 135, 136, 19,
+ -1, 21, 22, 23, 24, -1, -1, -1, -1, -1,
+ 30, 31, 32, 33, 34, 35, 36, -1, -1, 39,
+ -1, -1, -1, -1, -1, -1, -1, -1, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, -1, 58, 59,
+ 60, -1, -1, 63, -1, -1, 66, 67, -1, 69,
+ 70, 71, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 84, 85, -1, -1, -1, -1,
+ -1, 91, -1, -1, 94, 95, -1, 97, 98, -1,
+ 100, -1, -1, -1, 104, -1, 106, 107, 108, -1,
+ 110, 111, 112, -1, 114, -1, -1, -1, -1, -1,
+ -1, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ -1, -1, -1, -1, 134, 135, 136, 19, -1, 21,
+ 22, 23, 24, -1, -1, -1, -1, -1, 30, 31,
+ 32, 33, 34, 35, 36, -1, -1, 39, -1, -1,
+ -1, -1, -1, -1, -1, -1, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, -1, 58, 59, 60, -1,
+ -1, 63, -1, -1, 66, 67, -1, 69, 70, 71,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 84, 85, -1, -1, -1, -1, -1, 91,
+ -1, -1, 94, 95, -1, 97, 98, -1, 100, -1,
+ -1, -1, 104, -1, 106, 107, 108, -1, 110, 111,
+ 112, -1, 114, -1, -1, -1, -1, -1, -1, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, -1, -1,
+ -1, -1, 134, 135, 136, 19, -1, 21, 22, 23,
+ 24, -1, -1, -1, -1, -1, 30, 31, 32, 33,
+ 34, 35, 36, -1, -1, 39, -1, -1, -1, -1,
+ -1, -1, -1, -1, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, -1, 58, 59, 60, -1, -1, 63,
+ -1, -1, 66, 67, -1, 69, 70, 71, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 84, 85, -1, -1, -1, -1, -1, 91, -1, -1,
+ 94, 95, -1, 97, 98, -1, 100, -1, -1, -1,
+ 104, -1, 106, 107, 108, -1, 110, 111, 112, -1,
+ 114, -1, -1, -1, -1, -1, -1, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, -1, -1, -1, -1,
+ 134, 135, 136, 19, -1, 21, 22, 23, 24, -1,
+ -1, -1, -1, -1, 30, 31, 32, 33, 34, 35,
+ 36, -1, -1, 39, -1, -1, -1, -1, -1, -1,
+ -1, -1, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, -1, 58, 59, 60, -1, -1, 63, -1, -1,
+ 66, 67, -1, 69, 70, 71, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 84, 85,
+ -1, -1, -1, -1, -1, 91, -1, -1, 94, 95,
+ -1, 97, 98, -1, -1, -1, -1, -1, 104, -1,
+ 106, 107, 108, -1, 110, 111, 112, -1, 114, -1,
+ -1, -1, -1, -1, -1, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, -1, -1, -1, -1, 134, 135,
+ 136, 19, -1, 21, 22, 23, 24, -1, -1, -1,
+ -1, -1, 30, 31, 32, 33, 34, 35, 36, -1,
+ -1, 39, -1, -1, -1, -1, -1, -1, -1, -1,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, -1,
+ 58, 59, 60, -1, -1, 63, -1, -1, 66, 67,
+ -1, 69, 70, 71, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 84, 85, -1, -1,
+ -1, -1, -1, 91, -1, -1, 94, 95, -1, 97,
+ 98, -1, -1, -1, -1, -1, 104, -1, 106, 107,
+ 108, -1, 110, 111, 112, -1, 114, -1, -1, -1,
+ -1, -1, -1, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, -1, -1, -1, -1, 134, 135, 136, 19,
+ -1, 21, 22, 23, 24, -1, -1, -1, -1, -1,
+ 30, 31, 32, 33, 34, 35, 36, -1, -1, 39,
+ -1, -1, -1, -1, -1, -1, -1, -1, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, -1, 58, 59,
+ 60, -1, -1, 63, -1, -1, 66, 67, -1, 69,
+ 70, 71, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 84, 85, -1, -1, -1, -1,
+ -1, 91, -1, -1, 94, 95, -1, 97, 98, -1,
+ -1, -1, -1, -1, 104, -1, 106, 107, 108, -1,
+ 110, 111, 112, -1, 114, -1, -1, -1, -1, -1,
+ -1, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ -1, -1, -1, -1, 134, 135, 136, 19, -1, 21,
+ 22, 23, 24, -1, -1, -1, -1, -1, 30, 31,
+ 32, 33, 34, 35, 36, -1, -1, 39, -1, -1,
+ -1, -1, -1, -1, -1, -1, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, -1, 58, 59, 60, -1,
+ -1, 63, -1, -1, 66, 67, -1, 69, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 88, -1, -1, 91,
+ -1, -1, 94, 95, -1, 97, 98, -1, -1, -1,
+ -1, -1, 104, -1, 106, 107, 108, -1, 110, 111,
+ 112, -1, 114, -1, -1, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, -1, -1, -1, -1, -1, -1,
+ -1, 19, 134, 21, 22, 23, 24, -1, -1, -1,
+ -1, -1, 30, 31, 32, 33, 34, 35, 36, -1,
+ -1, 39, -1, -1, -1, -1, -1, -1, -1, -1,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, -1,
+ 58, 59, 60, -1, -1, 63, -1, -1, 66, 67,
+ -1, 69, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 91, -1, -1, 94, 95, -1, 97,
+ 98, -1, 100, -1, -1, -1, 104, -1, 106, 107,
+ 108, -1, 110, 111, 112, -1, 114, -1, -1, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, -1, -1,
+ -1, -1, -1, -1, -1, 19, 134, 21, 22, 23,
+ 24, -1, -1, -1, -1, -1, 30, 31, 32, 33,
+ 34, 35, 36, -1, -1, 39, -1, -1, -1, -1,
+ -1, -1, -1, -1, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, -1, 58, 59, 60, -1, -1, 63,
+ -1, -1, 66, 67, -1, 69, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 91, -1, -1,
+ 94, 95, -1, 97, 98, -1, 100, -1, -1, -1,
+ 104, -1, 106, 107, 108, -1, 110, 111, 112, -1,
+ 114, -1, -1, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, -1, -1, -1, -1, -1, -1, -1, 19,
+ 134, 21, 22, 23, 24, -1, -1, -1, -1, -1,
+ 30, 31, 32, 33, 34, 35, 36, -1, -1, 39,
+ -1, -1, -1, -1, -1, -1, -1, -1, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, -1, 58, 59,
+ 60, -1, -1, 63, -1, -1, 66, 67, -1, 69,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 91, -1, -1, 94, 95, -1, 97, 98, -1,
+ -1, -1, -1, -1, 104, -1, 106, 107, 108, -1,
+ 110, 111, 112, -1, 114, -1, -1, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, -1, -1, -1, -1,
+ -1, -1, -1, 19, 134, 21, 22, 23, 24, -1,
+ -1, -1, -1, -1, 30, 31, 32, 33, 34, 35,
+ 36, -1, -1, 39, -1, -1, -1, -1, -1, -1,
+ -1, -1, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, -1, 58, 59, 60, -1, -1, 63, -1, -1,
+ 66, 67, -1, 69, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 91, -1, -1, 94, 95,
+ -1, 97, 98, -1, -1, -1, -1, -1, 104, -1,
+ 106, 107, 108, -1, 110, 111, 112, -1, 114, -1,
+ -1, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ -1, -1, -1, -1, -1, -1, -1, 19, 134, 21,
+ 22, 23, 24, -1, -1, -1, -1, -1, 30, 31,
+ 32, 33, 34, 35, 36, -1, -1, 39, -1, -1,
+ -1, -1, -1, -1, -1, -1, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, -1, 58, 59, 60, -1,
+ -1, 63, -1, -1, 66, 67, -1, 69, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 91,
+ -1, -1, 94, 95, -1, 97, 98, -1, -1, -1,
+ -1, -1, 104, -1, 106, 107, 108, -1, 110, 111,
+ 112, -1, 114, -1, -1, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, -1, -1, -1, -1, -1, -1,
+ -1, 19, 134, 21, 22, 23, 24, -1, -1, -1,
+ -1, -1, 30, 31, 32, 33, 34, 35, 36, -1,
+ -1, 39, -1, -1, -1, -1, -1, -1, -1, -1,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, -1,
+ 58, 59, 60, -1, -1, 63, -1, -1, 66, 67,
+ -1, 69, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 91, -1, -1, 94, 95, -1, 97,
+ 98, -1, -1, 51, 52, -1, 104, 55, 106, 107,
+ 108, -1, 110, 111, 112, -1, 114, -1, -1, -1,
+ -1, -1, 70, 71, 72, 73, 74, 75, 76, 77,
+ -1, -1, 80, 81, -1, -1, 134, -1, 86, 87,
+ 88, 89, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 100, 101, 102, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, -1, 135, 136, 51,
+ 52, -1, -1, 55, -1, 143, 144, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 70, 71,
+ 72, 73, 74, 75, 76, 77, -1, -1, 80, 81,
+ -1, -1, -1, -1, 86, 87, 88, 89, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 100, 101,
+ 102, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 124, 125, 126, 127, 128, 129, 130, 131,
+ 132, 133, -1, 135, 136, 51, 52, -1, -1, 55,
+ -1, 143, 144, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 70, 71, 72, 73, 74, 75,
+ 76, 77, -1, -1, 80, 81, -1, -1, -1, -1,
+ 86, 87, 88, 89, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 100, 101, 102, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 124, 125,
+ 126, 127, 128, 129, 130, 131, 132, 133, -1, 135,
+ 136, 51, 52, -1, -1, 55, -1, 143, 144, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 70, 71, 72, 73, 74, 75, 76, 77, -1, -1,
+ 80, 81, -1, -1, -1, -1, 86, 87, 88, 89,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 100, 101, 102, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 133, -1, 135, 136, 51, 52, -1,
+ -1, 55, -1, 143, 144, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 70, 71, 72, 73,
+ 74, 75, 76, 77, -1, -1, 80, 81, -1, -1,
+ -1, -1, 86, 87, 88, 89, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 100, 101, 102, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
+ -1, 135, 136, 51, 52, -1, -1, 55, -1, 143,
+ 144, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 70, 71, 72, 73, 74, 75, 76, 77,
+ -1, -1, 80, 81, -1, -1, -1, -1, 86, 87,
+ 88, 89, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 100, 101, 102, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, -1, 135, 136, 51,
+ 52, -1, -1, 55, -1, 143, 144, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 70, 71,
+ 72, 73, 74, 75, 76, 77, -1, -1, 80, 81,
+ -1, -1, -1, -1, 86, 87, 88, 89, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 100, 101,
+ 102, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 124, 125, 126, 127, 128, 129, 130, 131,
+ 132, 133, -1, 135, 136, 51, 52, -1, -1, 55,
+ -1, 143, 144, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 70, 71, 72, 73, 74, 75,
+ 76, 77, -1, -1, 80, 81, -1, -1, -1, -1,
+ 86, 87, 88, 89, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 100, 101, 102, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 124, 125,
+ 126, 127, 128, 129, 130, 131, 132, 133, -1, 135,
+ 136, 51, 52, -1, -1, 55, -1, 143, 144, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 70, 71, 72, 73, 74, 75, 76, 77, -1, -1,
+ 80, 81, -1, -1, -1, -1, 86, 87, 88, 89,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 100, 101, 102, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 133, -1, 135, 136, 51, 52, -1,
+ -1, 55, -1, 143, 144, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 70, 71, 72, 73,
+ 74, 75, 76, 77, -1, -1, 80, 81, -1, -1,
+ -1, -1, 86, 87, 88, 89, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 100, 101, 102, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
+ -1, 135, 136, 51, 52, -1, -1, 55, -1, 143,
+ 144, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 70, 71, 72, 73, 74, 75, 76, 77,
+ -1, -1, 80, 81, -1, -1, -1, -1, 86, 87,
+ 88, 89, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 100, 101, 102, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, -1, 135, 136, 51,
+ 52, -1, -1, 55, -1, 143, 144, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 70, 71,
+ 72, 73, 74, 75, 76, 77, -1, -1, 80, 81,
+ -1, -1, -1, -1, 86, 87, 88, 89, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 100, 101,
+ 102, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 124, 125, 126, 127, 128, 129, 130, 131,
+ 132, 133, -1, 135, 136, 51, 52, -1, -1, 55,
+ -1, 143, 144, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 70, 71, 72, 73, 74, 75,
+ 76, 77, -1, -1, 80, 81, -1, -1, -1, -1,
+ 86, 87, 88, 89, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 100, 101, 102, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 124, 125,
+ 126, 127, 128, 129, 130, 131, 132, 133, -1, 135,
+ 136, 51, 52, -1, -1, 55, -1, 143, 144, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 70, 71, 72, 73, 74, 75, 76, 77, -1, -1,
+ 80, 81, -1, -1, -1, -1, 86, 87, 88, 89,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 100, 101, 102, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 133, -1, 135, 136, 51, 52, -1,
+ -1, 55, -1, 143, 144, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 70, 71, 72, 73,
+ 74, 75, 76, 77, -1, -1, 80, 81, -1, -1,
+ -1, -1, 86, 87, 88, 89, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 100, 101, 102, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
+ -1, 135, 136, 51, 52, -1, -1, 55, -1, 143,
+ 144, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 70, 71, 72, 73, 74, 75, 76, 77,
+ -1, -1, 80, 81, -1, -1, -1, -1, 86, 87,
+ 88, 89, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 100, 101, 102, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 44, -1,
+ -1, -1, -1, -1, -1, -1, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, -1, 135, 136, -1,
+ -1, -1, -1, -1, -1, 143, 72, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83, -1, -1,
+ -1, -1, 88, 89, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 101, -1, -1, -1, -1,
+ 44, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 122, -1, 124, 125,
+ 126, 127, 128, 129, 130, 131, 132, 133, 72, 73,
+ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ -1, -1, -1, -1, 88, 89, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 101, -1, -1,
+ -1, -1, 44, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 122, -1,
+ 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, -1, -1, -1, -1, 88, 89, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 101,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 122, -1, 124, 125, 126, 127, 128, 129, 130, 131,
+ 132, 133, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, -1, -1, -1, -1, 88, 89,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 101, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 122, -1, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 133, -1, -1, -1, -1, -1, -1,
+ -1, -1, 142, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, -1, -1, -1, -1, 88,
+ 89, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 101, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 122, -1, 124, 125, 126, 127, 128,
+ 129, 130, 131, 132, 133, -1, -1, -1, -1, -1,
+ -1, -1, -1, 142, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, -1, -1, -1, -1,
+ 88, 89, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 101, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 122, -1, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, -1, -1, -1, -1,
+ -1, -1, -1, -1, 142, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, -1, -1, -1,
+ -1, 88, 89, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 101, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 122, -1, 124, 125, 126,
+ 127, 128, 129, 130, 131, 132, 133, -1, -1, -1,
+ -1, -1, -1, -1, -1, 142, 72, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83, -1, -1,
+ -1, -1, 88, 89, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 101, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 122, -1, 124, 125,
+ 126, 127, 128, 129, 130, 131, 132, 133, 72, 73,
+ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ -1, -1, -1, -1, 88, 89, 72, 73, 74, 75,
+ 76, 77, -1, -1, 80, 81, -1, 101, -1, -1,
+ -1, -1, 88, 89, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 101, -1, -1, -1, -1,
+ 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
+ -1, -1, -1, -1, -1, -1, -1, -1, 124, 125,
+ 126, 127, 128, 129, 130, 131, 132, 133
+};
+
+/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
+ state STATE-NUM. */
+static const yytype_int16 yystos[] =
+{
+ 0, 150, 151, 1, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 19, 21, 22, 23, 24, 30,
+ 31, 32, 33, 34, 35, 36, 39, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 58,
+ 59, 60, 63, 66, 67, 69, 70, 71, 84, 85,
+ 91, 94, 95, 97, 98, 100, 104, 106, 107, 108,
+ 110, 111, 112, 114, 134, 135, 136, 152, 153, 154,
+ 160, 161, 163, 166, 168, 170, 171, 174, 175, 177,
+ 178, 179, 181, 182, 191, 205, 222, 243, 244, 275,
+ 276, 277, 281, 282, 283, 289, 290, 291, 293, 294,
+ 295, 296, 297, 298, 334, 347, 0, 154, 21, 22,
+ 30, 31, 32, 39, 51, 55, 69, 88, 91, 94,
+ 134, 166, 168, 183, 184, 205, 222, 295, 298, 334,
+ 184, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 45, 46, 47, 48, 49,
+ 50, 51, 52, 55, 70, 71, 72, 73, 74, 75,
+ 76, 77, 80, 81, 86, 87, 88, 89, 100, 101,
+ 102, 124, 125, 126, 127, 128, 129, 130, 131, 132,
+ 133, 135, 136, 143, 144, 185, 189, 190, 297, 329,
+ 206, 91, 163, 166, 168, 169, 182, 222, 295, 296,
+ 298, 169, 212, 214, 69, 91, 175, 182, 222, 227,
+ 295, 298, 33, 34, 35, 36, 48, 49, 50, 51,
+ 55, 106, 185, 186, 187, 291, 115, 118, 119, 146,
+ 148, 169, 285, 286, 287, 340, 344, 345, 346, 51,
+ 69, 100, 102, 103, 135, 174, 191, 197, 200, 203,
+ 277, 332, 333, 197, 197, 144, 194, 195, 198, 199,
+ 347, 194, 199, 144, 341, 186, 155, 138, 191, 222,
+ 191, 191, 191, 55, 1, 94, 157, 158, 160, 176,
+ 177, 347, 207, 209, 192, 203, 332, 347, 191, 331,
+ 332, 347, 91, 142, 181, 222, 295, 298, 210, 53,
+ 54, 56, 63, 69, 107, 185, 292, 63, 64, 65,
+ 116, 117, 278, 279, 61, 278, 62, 278, 63, 278,
+ 63, 278, 58, 59, 170, 191, 191, 340, 346, 40,
+ 41, 42, 43, 44, 37, 38, 51, 53, 54, 55,
+ 56, 69, 83, 94, 100, 101, 102, 103, 128, 131,
+ 144, 301, 302, 303, 304, 305, 308, 309, 310, 311,
+ 313, 314, 315, 316, 318, 319, 320, 323, 324, 325,
+ 326, 327, 347, 301, 303, 28, 242, 121, 142, 94,
+ 100, 178, 121, 25, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 88, 89, 93, 101,
+ 122, 124, 125, 126, 127, 128, 129, 130, 131, 132,
+ 133, 90, 105, 140, 147, 338, 90, 338, 339, 26,
+ 138, 246, 277, 92, 92, 194, 199, 246, 163, 51,
+ 55, 183, 58, 59, 302, 125, 299, 90, 140, 338,
+ 221, 330, 90, 147, 337, 156, 157, 55, 301, 301,
+ 16, 223, 344, 121, 90, 140, 338, 92, 92, 223,
+ 169, 169, 55, 90, 140, 338, 25, 107, 142, 288,
+ 340, 115, 287, 20, 248, 344, 57, 57, 191, 191,
+ 191, 93, 142, 201, 202, 347, 57, 201, 202, 85,
+ 196, 197, 203, 332, 347, 197, 163, 340, 342, 163,
+ 345, 159, 138, 157, 90, 338, 92, 160, 176, 145,
+ 340, 346, 342, 157, 342, 141, 202, 343, 346, 202,
+ 343, 139, 343, 55, 178, 179, 180, 142, 90, 140,
+ 338, 144, 239, 313, 318, 63, 278, 280, 284, 285,
+ 63, 279, 61, 62, 63, 63, 101, 101, 154, 169,
+ 169, 169, 169, 160, 163, 163, 57, 121, 57, 344,
+ 317, 85, 313, 318, 121, 156, 191, 142, 328, 347,
+ 51, 142, 328, 344, 142, 312, 191, 142, 312, 51,
+ 142, 312, 34, 51, 121, 156, 241, 100, 170, 191,
+ 203, 204, 176, 142, 181, 142, 161, 162, 170, 182,
+ 191, 193, 204, 222, 298, 165, 191, 191, 191, 191,
+ 191, 191, 191, 191, 191, 191, 191, 191, 191, 191,
+ 164, 191, 191, 191, 191, 191, 191, 191, 191, 191,
+ 191, 191, 191, 51, 52, 55, 189, 194, 335, 336,
+ 196, 203, 51, 52, 55, 189, 194, 335, 51, 55,
+ 335, 247, 245, 162, 191, 193, 162, 193, 99, 173,
+ 219, 300, 218, 51, 55, 183, 335, 196, 335, 156,
+ 163, 167, 15, 13, 271, 347, 121, 121, 157, 16,
+ 51, 55, 196, 51, 55, 157, 27, 224, 344, 224,
+ 51, 55, 196, 51, 55, 216, 188, 157, 25, 248,
+ 191, 203, 15, 191, 191, 191, 341, 100, 191, 200,
+ 332, 191, 333, 342, 145, 340, 202, 202, 342, 145,
+ 186, 152, 139, 193, 342, 160, 208, 332, 178, 180,
+ 51, 55, 196, 51, 55, 313, 211, 142, 63, 157,
+ 285, 191, 191, 51, 69, 100, 228, 318, 342, 342,
+ 142, 174, 191, 15, 51, 69, 305, 310, 327, 85,
+ 311, 316, 323, 325, 318, 320, 325, 51, 318, 174,
+ 191, 15, 79, 126, 233, 235, 347, 191, 202, 342,
+ 180, 142, 44, 121, 44, 90, 140, 338, 34, 35,
+ 36, 51, 55, 63, 91, 97, 98, 100, 102, 127,
+ 254, 255, 257, 258, 259, 260, 263, 264, 265, 267,
+ 268, 269, 270, 290, 294, 254, 341, 92, 92, 194,
+ 199, 141, 202, 92, 92, 195, 199, 195, 199, 233,
+ 233, 172, 344, 169, 156, 141, 15, 342, 185, 191,
+ 204, 272, 347, 18, 226, 347, 17, 225, 226, 92,
+ 92, 141, 92, 92, 226, 213, 215, 141, 169, 186,
+ 139, 254, 15, 202, 223, 191, 201, 85, 332, 139,
+ 342, 343, 141, 236, 341, 29, 113, 240, 139, 142,
+ 315, 342, 142, 85, 44, 44, 328, 344, 142, 312,
+ 142, 312, 142, 312, 142, 312, 312, 44, 44, 230,
+ 232, 234, 304, 306, 307, 310, 318, 319, 321, 322,
+ 325, 327, 156, 100, 191, 180, 160, 191, 51, 55,
+ 196, 51, 55, 57, 55, 51, 141, 257, 261, 262,
+ 263, 51, 139, 266, 267, 269, 51, 34, 51, 51,
+ 257, 263, 142, 93, 126, 142, 90, 142, 57, 123,
+ 162, 193, 170, 193, 173, 92, 162, 193, 162, 193,
+ 173, 246, 242, 156, 157, 233, 220, 344, 15, 93,
+ 273, 347, 157, 14, 274, 347, 169, 15, 92, 15,
+ 157, 157, 224, 40, 41, 223, 191, 157, 342, 202,
+ 145, 146, 156, 157, 229, 142, 100, 342, 191, 191,
+ 318, 325, 318, 318, 191, 191, 236, 236, 91, 222,
+ 142, 328, 328, 142, 231, 222, 142, 231, 142, 231,
+ 15, 191, 141, 257, 141, 142, 142, 139, 142, 142,
+ 142, 51, 259, 256, 257, 55, 268, 269, 191, 191,
+ 162, 193, 15, 139, 157, 156, 91, 182, 222, 295,
+ 298, 223, 157, 223, 15, 15, 217, 169, 169, 157,
+ 226, 248, 249, 51, 237, 238, 314, 15, 139, 318,
+ 318, 142, 315, 312, 142, 312, 312, 312, 126, 126,
+ 55, 90, 306, 310, 142, 230, 231, 322, 325, 318,
+ 321, 325, 318, 257, 263, 262, 269, 256, 142, 139,
+ 15, 55, 90, 140, 338, 157, 157, 157, 223, 223,
+ 25, 226, 250, 142, 341, 142, 318, 142, 318, 51,
+ 55, 328, 142, 231, 142, 231, 142, 231, 142, 231,
+ 231, 142, 142, 257, 51, 55, 196, 51, 55, 271,
+ 225, 15, 157, 157, 254, 15, 238, 318, 312, 318,
+ 325, 318, 318, 262, 263, 141, 250, 250, 251, 252,
+ 253, 231, 142, 231, 231, 231, 142, 15, 15, 223,
+ 40, 41, 318, 157, 169, 169, 231, 250, 223, 223,
+ 157, 157, 250, 250
+};
+
+/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */
+static const yytype_int16 yyr1[] =
+{
+ 0, 149, 150, 151, 152, 153, 153, 153, 153, 154,
+ 155, 154, 156, 157, 158, 158, 158, 158, 159, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 161, 161, 161, 161, 161, 161, 161,
+ 161, 161, 161, 161, 161, 162, 162, 162, 163, 163,
+ 163, 163, 163, 164, 163, 165, 163, 163, 166, 167,
+ 168, 169, 170, 170, 171, 171, 172, 173, 174, 174,
+ 174, 174, 174, 174, 174, 174, 174, 174, 174, 175,
+ 175, 176, 176, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 178, 178, 179, 179, 180, 180, 181,
+ 181, 181, 181, 181, 181, 181, 181, 182, 182, 182,
+ 182, 182, 182, 182, 182, 182, 183, 183, 184, 184,
+ 184, 185, 185, 185, 185, 185, 186, 186, 187, 188,
+ 187, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 190, 190, 190, 190, 190, 190, 190, 190, 190,
+ 190, 190, 190, 190, 190, 190, 190, 190, 190, 190,
+ 190, 190, 190, 190, 190, 190, 190, 190, 190, 190,
+ 190, 190, 190, 190, 190, 190, 190, 190, 190, 190,
+ 190, 191, 191, 191, 191, 191, 191, 191, 191, 191,
+ 191, 191, 191, 191, 191, 191, 191, 191, 191, 191,
+ 191, 191, 191, 191, 191, 191, 191, 191, 191, 191,
+ 191, 191, 191, 191, 191, 191, 191, 191, 191, 191,
+ 191, 191, 191, 191, 191, 191, 191, 191, 191, 191,
+ 191, 191, 192, 192, 192, 192, 193, 193, 194, 194,
+ 194, 195, 195, 196, 196, 196, 196, 196, 197, 197,
+ 197, 197, 197, 198, 199, 200, 200, 201, 201, 202,
+ 203, 203, 203, 203, 203, 203, 204, 204, 204, 205,
+ 205, 205, 205, 205, 205, 205, 205, 206, 205, 207,
+ 208, 205, 209, 205, 205, 205, 205, 205, 205, 205,
+ 205, 205, 205, 205, 205, 205, 210, 211, 205, 205,
+ 205, 212, 213, 205, 214, 215, 205, 205, 205, 205,
+ 205, 205, 216, 217, 205, 218, 205, 219, 220, 205,
+ 221, 205, 205, 205, 205, 205, 205, 205, 222, 223,
+ 223, 223, 224, 224, 225, 225, 226, 226, 227, 227,
+ 228, 228, 228, 228, 228, 228, 228, 228, 229, 228,
+ 230, 230, 230, 230, 231, 231, 232, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 233, 233, 234, 235, 235, 235, 236, 236, 237,
+ 237, 238, 238, 239, 239, 240, 240, 241, 242, 243,
+ 243, 243, 243, 244, 244, 244, 244, 244, 244, 244,
+ 244, 244, 245, 246, 247, 246, 248, 249, 249, 250,
+ 251, 250, 252, 250, 253, 250, 254, 254, 254, 254,
+ 254, 254, 254, 254, 254, 255, 255, 256, 256, 257,
+ 257, 258, 258, 259, 259, 259, 259, 259, 259, 259,
+ 259, 259, 259, 259, 260, 260, 261, 261, 261, 261,
+ 261, 261, 262, 262, 263, 263, 264, 264, 264, 265,
+ 265, 266, 266, 266, 267, 267, 268, 268, 269, 269,
+ 269, 270, 271, 271, 272, 272, 272, 273, 273, 274,
+ 274, 275, 275, 275, 275, 276, 276, 277, 277, 277,
+ 277, 278, 278, 279, 280, 279, 279, 279, 281, 281,
+ 282, 282, 283, 284, 284, 285, 285, 286, 286, 287,
+ 288, 287, 289, 289, 290, 290, 290, 291, 292, 292,
+ 292, 292, 292, 292, 293, 293, 294, 294, 294, 294,
+ 295, 295, 295, 295, 295, 296, 296, 297, 297, 297,
+ 297, 297, 297, 297, 297, 297, 298, 298, 299, 300,
+ 299, 301, 301, 302, 302, 302, 303, 303, 303, 303,
+ 304, 304, 305, 305, 306, 306, 307, 307, 308, 308,
+ 309, 309, 310, 310, 311, 311, 311, 311, 312, 312,
+ 312, 313, 313, 313, 313, 313, 313, 313, 313, 313,
+ 313, 313, 313, 313, 313, 313, 314, 314, 314, 314,
+ 314, 315, 315, 316, 317, 316, 318, 318, 319, 320,
+ 321, 322, 322, 323, 323, 324, 324, 325, 325, 326,
+ 326, 327, 327, 327, 328, 328, 328, 329, 330, 329,
+ 331, 331, 332, 332, 333, 333, 333, 333, 333, 333,
+ 333, 333, 334, 334, 334, 335, 335, 335, 335, 336,
+ 336, 336, 337, 337, 338, 338, 339, 339, 340, 340,
+ 341, 341, 342, 343, 343, 343, 344, 344, 345, 345,
+ 346, 346, 347
+};
+
+/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */
+static const yytype_int8 yyr2[] =
+{
+ 0, 2, 0, 2, 2, 1, 1, 3, 2, 1,
+ 0, 5, 4, 2, 1, 1, 3, 2, 0, 4,
+ 2, 3, 3, 3, 3, 3, 4, 1, 3, 3,
+ 3, 3, 1, 3, 3, 6, 5, 5, 5, 5,
+ 4, 6, 4, 6, 3, 1, 3, 1, 1, 3,
+ 3, 3, 2, 0, 4, 0, 4, 1, 2, 0,
+ 5, 1, 1, 1, 1, 4, 0, 5, 2, 3,
+ 4, 5, 4, 5, 2, 2, 2, 2, 2, 1,
+ 3, 1, 3, 1, 2, 3, 5, 2, 4, 2,
+ 4, 1, 3, 1, 3, 2, 3, 1, 2, 1,
+ 4, 3, 3, 3, 3, 2, 1, 1, 4, 3,
+ 3, 3, 3, 2, 1, 1, 1, 1, 2, 1,
+ 3, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+ 4, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 3, 3, 6, 5, 5, 5, 5, 4, 3,
+ 3, 2, 2, 3, 2, 2, 3, 3, 3, 3,
+ 3, 3, 4, 4, 2, 2, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 2,
+ 2, 3, 3, 3, 3, 6, 6, 4, 6, 4,
+ 6, 1, 1, 2, 4, 2, 1, 3, 3, 5,
+ 3, 1, 1, 1, 2, 2, 4, 2, 1, 2,
+ 2, 4, 1, 0, 2, 2, 1, 2, 1, 2,
+ 1, 1, 2, 3, 3, 4, 3, 4, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 0, 4, 0,
+ 0, 5, 0, 3, 3, 3, 2, 3, 3, 1,
+ 2, 4, 3, 2, 1, 2, 0, 0, 5, 6,
+ 6, 0, 0, 7, 0, 0, 7, 5, 4, 9,
+ 11, 11, 0, 0, 9, 0, 6, 0, 0, 8,
+ 0, 5, 4, 4, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 1, 1, 5, 1, 2, 1, 1,
+ 1, 4, 6, 3, 5, 2, 4, 1, 0, 4,
+ 4, 2, 2, 1, 2, 0, 6, 8, 4, 6,
+ 4, 3, 6, 2, 4, 6, 2, 4, 2, 4,
+ 1, 1, 1, 0, 4, 1, 4, 1, 4, 1,
+ 3, 1, 1, 4, 1, 3, 3, 0, 5, 2,
+ 4, 5, 5, 2, 4, 4, 3, 3, 3, 2,
+ 1, 4, 0, 5, 0, 5, 5, 1, 1, 1,
+ 0, 6, 0, 8, 0, 8, 1, 2, 2, 4,
+ 1, 3, 1, 3, 1, 2, 3, 1, 3, 1,
+ 3, 1, 3, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 3, 2, 1, 3, 5, 1,
+ 3, 5, 1, 3, 2, 1, 1, 3, 2, 3,
+ 2, 1, 3, 1, 1, 3, 3, 2, 2, 2,
+ 1, 1, 6, 1, 1, 1, 1, 2, 1, 2,
+ 1, 1, 1, 1, 1, 1, 2, 1, 1, 2,
+ 3, 1, 2, 1, 0, 4, 1, 2, 2, 3,
+ 2, 3, 1, 1, 2, 1, 2, 1, 2, 1,
+ 0, 4, 2, 3, 1, 4, 2, 2, 1, 1,
+ 1, 1, 1, 2, 2, 3, 1, 1, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+ 4, 1, 1, 3, 5, 3, 1, 2, 4, 2,
+ 2, 2, 2, 1, 2, 1, 1, 3, 1, 3,
+ 1, 1, 2, 1, 4, 2, 2, 1, 2, 1,
+ 0, 6, 8, 4, 6, 4, 6, 2, 4, 6,
+ 2, 4, 2, 4, 1, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 0, 4, 1, 3, 2, 2,
+ 2, 1, 3, 1, 3, 1, 1, 2, 1, 1,
+ 1, 2, 2, 1, 2, 1, 1, 1, 0, 4,
+ 1, 2, 1, 3, 3, 3, 2, 2, 3, 3,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,
+ 0, 2, 2, 0, 1, 1, 1, 1, 1, 1,
+ 1, 2, 0
+};
+
+
+enum { YYENOMEM = -2 };
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+#define YYNOMEM goto yyexhaustedlab
+
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+ do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (&yylloc, p, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+ while (0)
+
+/* Backward compatibility with an undocumented macro.
+ Use YYerror or YYUNDEF. */
+#define YYERRCODE YYUNDEF
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (N) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (0)
+#endif
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+
+/* YYLOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+# ifndef YYLOCATION_PRINT
+
+# if defined YY_LOCATION_PRINT
+
+ /* Temporary convenience wrapper in case some people defined the
+ undocumented and private YY_LOCATION_PRINT macros. */
+# define YYLOCATION_PRINT(File, Loc, p) YY_LOCATION_PRINT(File, *(Loc), p)
+
+# elif defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+
+/* Print *YYLOCP on YYO. Private, do not rely on its existence. */
+
+YY_ATTRIBUTE_UNUSED
+static int
+yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp)
+{
+ int res = 0;
+ int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0;
+ if (0 <= yylocp->first_line)
+ {
+ res += YYFPRINTF (yyo, "%d", yylocp->first_line);
+ if (0 <= yylocp->first_column)
+ res += YYFPRINTF (yyo, ".%d", yylocp->first_column);
+ }
+ if (0 <= yylocp->last_line)
+ {
+ if (yylocp->first_line < yylocp->last_line)
+ {
+ res += YYFPRINTF (yyo, "-%d", yylocp->last_line);
+ if (0 <= end_col)
+ res += YYFPRINTF (yyo, ".%d", end_col);
+ }
+ else if (0 <= end_col && yylocp->first_column < end_col)
+ res += YYFPRINTF (yyo, "-%d", end_col);
+ }
+ return res;
+}
+
+# define YYLOCATION_PRINT yy_location_print_
+
+ /* Temporary convenience wrapper in case some people defined the
+ undocumented and private YY_LOCATION_PRINT macros. */
+# define YY_LOCATION_PRINT(File, Loc, p) YYLOCATION_PRINT(File, &(Loc), p)
+
+# else
+
+# define YYLOCATION_PRINT(File, Loc, p) ((void) 0)
+ /* Temporary convenience wrapper in case some people defined the
+ undocumented and private YY_LOCATION_PRINT macros. */
+# define YY_LOCATION_PRINT YYLOCATION_PRINT
+
+# endif
+# endif /* !defined YYLOCATION_PRINT */
+
+
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location, p) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Kind, Value, Location, p); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+
+/*-----------------------------------.
+| Print this symbol's value on YYO. |
+`-----------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyo,
+ yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, parser_state *p)
+{
+ FILE *yyoutput = yyo;
+ YY_USE (yyoutput);
+ YY_USE (yylocationp);
+ YY_USE (p);
+ if (!yyvaluep)
+ return;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+switch (yykind)
+ {
+ default:
+ break;
+ }
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+/*---------------------------.
+| Print this symbol on YYO. |
+`---------------------------*/
+
+static void
+yy_symbol_print (FILE *yyo,
+ yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, parser_state *p)
+{
+ YYFPRINTF (yyo, "%s %s (",
+ yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
+
+ YYLOCATION_PRINT (yyo, yylocationp, p);
+ YYFPRINTF (yyo, ": ");
+ yy_symbol_value_print (yyo, yykind, yyvaluep, yylocationp, p);
+ YYFPRINTF (yyo, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop, parser_state *p)
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top, p) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top), p); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp,
+ int yyrule, parser_state *p)
+{
+ int yylno = yyrline[yyrule];
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr,
+ YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
+ &yyvsp[(yyi + 1) - (yynrhs)],
+ &(yylsp[(yyi + 1) - (yynrhs)]), p);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule, p) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyssp, yyvsp, yylsp, Rule, p); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+#ifndef yydebug
+int yydebug;
+#endif
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args) ((void) 0)
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location, p)
+# define YY_STACK_PRINT(Bottom, Top, p)
+# define YY_REDUCE_PRINT(Rule, p)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+/* Context of a parse error. */
+typedef struct
+{
+ yy_state_t *yyssp;
+ yysymbol_kind_t yytoken;
+ YYLTYPE *yylloc;
+} yypcontext_t;
+
+/* Put in YYARG at most YYARGN of the expected tokens given the
+ current YYCTX, and return the number of tokens stored in YYARG. If
+ YYARG is null, return the number of expected tokens (guaranteed to
+ be less than YYNTOKENS). Return YYENOMEM on memory exhaustion.
+ Return 0 if there are more than YYARGN expected tokens, yet fill
+ YYARG up to YYARGN. */
+static int
+yypcontext_expected_tokens (const yypcontext_t *yyctx,
+ yysymbol_kind_t yyarg[], int yyargn)
+{
+ /* Actual size of YYARG. */
+ int yycount = 0;
+ int yyn = yypact[+*yyctx->yyssp];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (!yyarg)
+ ++yycount;
+ else if (yycount == yyargn)
+ return 0;
+ else
+ yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx);
+ }
+ }
+ if (yyarg && yycount == 0 && 0 < yyargn)
+ yyarg[0] = YYSYMBOL_YYEMPTY;
+ return yycount;
+}
+
+
+
+
+#ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S)))
+# else
+/* Return the length of YYSTR. */
+static YYPTRDIFF_T
+yystrlen (const char *yystr)
+{
+ YYPTRDIFF_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+#endif
+
+#ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+#endif
+
+#ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYPTRDIFF_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYPTRDIFF_T yyn = 0;
+ char const *yyp = yystr;
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ else
+ goto append;
+
+ append:
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (yyres)
+ return yystpcpy (yyres, yystr) - yyres;
+ else
+ return yystrlen (yystr);
+}
+#endif
+
+
+static int
+yy_syntax_error_arguments (const yypcontext_t *yyctx,
+ yysymbol_kind_t yyarg[], int yyargn)
+{
+ /* Actual size of YYARG. */
+ int yycount = 0;
+ /* There are many possibilities here to consider:
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yyctx->yytoken != YYSYMBOL_YYEMPTY)
+ {
+ int yyn;
+ if (yyarg)
+ yyarg[yycount] = yyctx->yytoken;
+ ++yycount;
+ yyn = yypcontext_expected_tokens (yyctx,
+ yyarg ? yyarg + 1 : yyarg, yyargn - 1);
+ if (yyn == YYENOMEM)
+ return YYENOMEM;
+ else
+ yycount += yyn;
+ }
+ return yycount;
+}
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg,
+ const yypcontext_t *yyctx, parser_state *p)
+{
+ enum { YYARGS_MAX = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULLPTR;
+ /* Arguments of yyformat: reported tokens (one for the "unexpected",
+ one per "expected"). */
+ yysymbol_kind_t yyarg[YYARGS_MAX];
+ /* Cumulated lengths of YYARG. */
+ YYPTRDIFF_T yysize = 0;
+
+ /* Actual size of YYARG. */
+ int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX);
+ if (yycount == YYENOMEM)
+ return YYENOMEM;
+
+ switch (yycount)
+ {
+#define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ default: /* Avoid compiler warnings. */
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+#undef YYCASE_
+ }
+
+ /* Compute error message size. Don't count the "%s"s, but reserve
+ room for the terminator. */
+ yysize = yystrlen (yyformat) - 2 * yycount + 1;
+ {
+ int yyi;
+ for (yyi = 0; yyi < yycount; ++yyi)
+ {
+ YYPTRDIFF_T yysize1
+ = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]);
+ if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
+ yysize = yysize1;
+ else
+ return YYENOMEM;
+ }
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return -1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]);
+ yyformat += 2;
+ }
+ else
+ {
+ ++yyp;
+ ++yyformat;
+ }
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg,
+ yysymbol_kind_t yykind, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, parser_state *p)
+{
+ YY_USE (yyvaluep);
+ YY_USE (yylocationp);
+ YY_USE (p);
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp, p);
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ switch (yykind)
+ {
+ default:
+ break;
+ }
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+int
+yyparse (parser_state *p)
+{
+/* Lookahead token kind. */
+int yychar;
+
+
+/* The semantic value of the lookahead symbol. */
+/* Default value used for initialization, for pacifying older GCCs
+ or non-GCC compilers. */
+#ifdef __cplusplus
+static const YYSTYPE yyval_default = {};
+(void) yyval_default;
+#else
+YY_INITIAL_VALUE (static const YYSTYPE yyval_default;)
+#endif
+YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
+
+/* Location data for the lookahead symbol. */
+static const YYLTYPE yyloc_default
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+ = { 1, 1, 1, 1 }
+# endif
+;
+YYLTYPE yylloc = yyloc_default;
+
+ /* Number of syntax errors so far. */
+ int yynerrs = 0;
+ YY_USE (yynerrs); /* Silence compiler warning. */
+
+ yy_state_fast_t yystate = 0;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus = 0;
+
+ /* Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* Their size. */
+ YYPTRDIFF_T yystacksize = YYINITDEPTH;
+
+ /* The state stack: array, bottom, top. */
+ yy_state_t yyssa[YYINITDEPTH];
+ yy_state_t *yyss = yyssa;
+ yy_state_t *yyssp = yyss;
+
+ /* The semantic value stack: array, bottom, top. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp = yyvs;
+
+ /* The location stack: array, bottom, top. */
+ YYLTYPE yylsa[YYINITDEPTH];
+ YYLTYPE *yyls = yylsa;
+ YYLTYPE *yylsp = yyls;
+
+ int yyn;
+ /* The return value of yyparse. */
+ int yyresult;
+ /* Lookahead symbol kind. */
+ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+ YYLTYPE yyloc;
+
+ /* The locations where the error started and ended. */
+ YYLTYPE yyerror_range[3];
+
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf;
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+
+
+#line 7200 "mrbgems/mruby-compiler/core/y.tab.c"
+
+ yylsp[0] = yylloc;
+ goto yysetstate;
+
+
+/*------------------------------------------------------------.
+| yynewstate -- push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+
+/*--------------------------------------------------------------------.
+| yysetstate -- set current state (the top of the stack) to yystate. |
+`--------------------------------------------------------------------*/
+yysetstate:
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+ YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
+ YY_IGNORE_USELESS_CAST_BEGIN
+ *yyssp = YY_CAST (yy_state_t, yystate);
+ YY_IGNORE_USELESS_CAST_END
+ YY_STACK_PRINT (yyss, yyssp, p);
+
+ if (yyss + yystacksize - 1 <= yyssp)
+#if !defined yyoverflow && !defined YYSTACK_RELOCATE
+ YYNOMEM;
+#else
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYPTRDIFF_T yysize = yyssp - yyss + 1;
+
+# if defined yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ yy_state_t *yyss1 = yyss;
+ YYSTYPE *yyvs1 = yyvs;
+ YYLTYPE *yyls1 = yyls;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * YYSIZEOF (*yyssp),
+ &yyvs1, yysize * YYSIZEOF (*yyvsp),
+ &yyls1, yysize * YYSIZEOF (*yylsp),
+ &yystacksize);
+ yyss = yyss1;
+ yyvs = yyvs1;
+ yyls = yyls1;
+ }
+# else /* defined YYSTACK_RELOCATE */
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ YYNOMEM;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yy_state_t *yyss1 = yyss;
+ union yyalloc *yyptr =
+ YY_CAST (union yyalloc *,
+ YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
+ if (! yyptr)
+ YYNOMEM;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ YYSTACK_RELOCATE (yyls_alloc, yyls);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+ yylsp = yyls + yysize - 1;
+
+ YY_IGNORE_USELESS_CAST_BEGIN
+ YYDPRINTF ((stderr, "Stack size increased to %ld\n",
+ YY_CAST (long, yystacksize)));
+ YY_IGNORE_USELESS_CAST_END
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
+
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token\n"));
+ yychar = yylex (&yylval, &yylloc, p);
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = YYEOF;
+ yytoken = YYSYMBOL_YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else if (yychar == YYerror)
+ {
+ /* The scanner already issued an error message, process directly
+ to error recovery. But do not keep the error token as
+ lookahead, it is too special and may lead us to an endless
+ loop in error recovery. */
+ yychar = YYUNDEF;
+ yytoken = YYSYMBOL_YYerror;
+ yyerror_range[1] = yylloc;
+ goto yyerrlab1;
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc, p);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc, p);
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+ *++yylsp = yylloc;
+
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ '$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ /* Default location. */
+ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+ yyerror_range[1] = yyloc;
+ YY_REDUCE_PRINT (yyn, p);
+ switch (yyn)
+ {
+ case 2: /* $@1: %empty */
+#line 2178 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ p->lstate = EXPR_BEG;
+ if (!p->locals) p->locals = cons(0,0);
+ }
+#line 7418 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 3: /* program: $@1 top_compstmt */
+#line 2183 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ p->tree = new_scope(p, (yyvsp[0].nd));
+ }
+#line 7426 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 4: /* top_compstmt: top_stmts opt_terms */
+#line 2189 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 7434 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 5: /* top_stmts: none */
+#line 2195 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_stmts(p, 0);
+ }
+#line 7442 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 6: /* top_stmts: top_stmt */
+#line 2199 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_stmts(p, (yyvsp[0].nd));
+ }
+#line 7450 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 7: /* top_stmts: top_stmts terms top_stmt */
+#line 2203 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = stmts_push(p, (yyvsp[-2].nd), newline_node((yyvsp[0].nd)));
+ }
+#line 7458 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 8: /* top_stmts: error top_stmt */
+#line 2207 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_stmts(p, 0);
+ }
+#line 7466 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 10: /* @2: %empty */
+#line 2214 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = local_switch(p);
+ nvars_block(p);
+ }
+#line 7475 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 11: /* top_stmt: "'BEGIN'" @2 '{' top_compstmt '}' */
+#line 2219 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ yyerror(&(yylsp[-4]), p, "BEGIN not supported");
+ local_resume(p, (yyvsp[-3].nd));
+ nvars_unnest(p);
+ (yyval.nd) = 0;
+ }
+#line 7486 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 12: /* bodystmt: compstmt opt_rescue opt_else opt_ensure */
+#line 2231 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ if ((yyvsp[-2].nd)) {
+ (yyval.nd) = new_rescue(p, (yyvsp[-3].nd), (yyvsp[-2].nd), (yyvsp[-1].nd));
+ }
+ else if ((yyvsp[-1].nd)) {
+ yywarning(p, "else without rescue is useless");
+ (yyval.nd) = stmts_push(p, (yyvsp[-3].nd), (yyvsp[-1].nd));
+ }
+ else {
+ (yyval.nd) = (yyvsp[-3].nd);
+ }
+ if ((yyvsp[0].nd)) {
+ if ((yyval.nd)) {
+ (yyval.nd) = new_ensure(p, (yyval.nd), (yyvsp[0].nd));
+ }
+ else {
+ (yyval.nd) = push((yyvsp[0].nd), new_nil(p));
+ }
+ }
+ }
+#line 7511 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 13: /* compstmt: stmts opt_terms */
+#line 2254 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 7519 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 14: /* stmts: none */
+#line 2260 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_stmts(p, 0);
+ }
+#line 7527 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 15: /* stmts: stmt */
+#line 2264 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_stmts(p, (yyvsp[0].nd));
+ }
+#line 7535 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 16: /* stmts: stmts terms stmt */
+#line 2268 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = stmts_push(p, (yyvsp[-2].nd), newline_node((yyvsp[0].nd)));
+ }
+#line 7543 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 17: /* stmts: error stmt */
+#line 2272 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_stmts(p, (yyvsp[0].nd));
+ }
+#line 7551 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 18: /* $@3: %empty */
+#line 2277 "mrbgems/mruby-compiler/core/parse.y"
+ {p->lstate = EXPR_FNAME;}
+#line 7557 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 19: /* stmt: "'alias'" fsym $@3 fsym */
+#line 2278 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_alias(p, (yyvsp[-2].id), (yyvsp[0].id));
+ }
+#line 7565 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 20: /* stmt: "'undef'" undef_list */
+#line 2282 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_undef(p, (yyvsp[0].nd));
+ }
+#line 7573 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 21: /* stmt: stmt "'if' modifier" expr_value */
+#line 2286 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_if(p, cond((yyvsp[0].nd)), (yyvsp[-2].nd), 0);
+ }
+#line 7581 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 22: /* stmt: stmt "'unless' modifier" expr_value */
+#line 2290 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_if(p, cond((yyvsp[0].nd)), 0, (yyvsp[-2].nd));
+ }
+#line 7589 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 23: /* stmt: stmt "'while' modifier" expr_value */
+#line 2294 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ if ((yyvsp[-2].nd) && node_type_p((yyvsp[-2].nd), NODE_BEGIN)) {
+ (yyval.nd) = new_while_mod(p, cond((yyvsp[0].nd)), (yyvsp[-2].nd));
+ }
+ else {
+ (yyval.nd) = new_while(p, cond((yyvsp[0].nd)), (yyvsp[-2].nd));
+ }
+ }
+#line 7602 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 24: /* stmt: stmt "'until' modifier" expr_value */
+#line 2303 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ if ((yyvsp[-2].nd) && node_type_p((yyvsp[-2].nd), NODE_BEGIN)) {
+ (yyval.nd) = new_until_mod(p, cond((yyvsp[0].nd)), (yyvsp[-2].nd));
+ }
+ else {
+ (yyval.nd) = new_until(p, cond((yyvsp[0].nd)), (yyvsp[-2].nd));
+ }
+ }
+#line 7615 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 25: /* stmt: stmt "'rescue' modifier" stmt */
+#line 2312 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_mod_rescue(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 7623 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 26: /* stmt: "'END'" '{' compstmt '}' */
+#line 2316 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ yyerror(&(yylsp[-3]), p, "END not supported");
+ (yyval.nd) = new_postexe(p, (yyvsp[-1].nd));
+ }
+#line 7632 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 28: /* stmt: mlhs '=' command_call */
+#line 2322 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_masgn(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 7640 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 29: /* stmt: lhs '=' mrhs */
+#line 2326 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_asgn(p, (yyvsp[-2].nd), new_array(p, (yyvsp[0].nd)));
+ }
+#line 7648 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 30: /* stmt: mlhs '=' arg */
+#line 2330 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_masgn(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 7656 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 31: /* stmt: mlhs '=' mrhs */
+#line 2334 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_masgn(p, (yyvsp[-2].nd), new_array(p, (yyvsp[0].nd)));
+ }
+#line 7664 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 33: /* command_asgn: lhs '=' command_rhs */
+#line 2341 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_asgn(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 7672 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 34: /* command_asgn: var_lhs tOP_ASGN command_rhs */
+#line 2345 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_op_asgn(p, (yyvsp[-2].nd), (yyvsp[-1].id), (yyvsp[0].nd));
+ }
+#line 7680 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 35: /* command_asgn: primary_value '[' opt_call_args ']' tOP_ASGN command_rhs */
+#line 2349 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_op_asgn(p, new_call(p, (yyvsp[-5].nd), intern_op(aref), (yyvsp[-3].nd), '.'), (yyvsp[-1].id), (yyvsp[0].nd));
+ }
+#line 7688 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 36: /* command_asgn: primary_value call_op "local variable or method" tOP_ASGN command_rhs */
+#line 2353 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_op_asgn(p, new_call(p, (yyvsp[-4].nd), (yyvsp[-2].id), 0, (yyvsp[-3].num)), (yyvsp[-1].id), (yyvsp[0].nd));
+ }
+#line 7696 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 37: /* command_asgn: primary_value call_op "constant" tOP_ASGN command_rhs */
+#line 2357 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_op_asgn(p, new_call(p, (yyvsp[-4].nd), (yyvsp[-2].id), 0, (yyvsp[-3].num)), (yyvsp[-1].id), (yyvsp[0].nd));
+ }
+#line 7704 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 38: /* command_asgn: primary_value "::" "constant" tOP_ASGN command_call */
+#line 2361 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ yyerror(&(yylsp[-4]), p, "constant re-assignment");
+ (yyval.nd) = 0;
+ }
+#line 7713 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 39: /* command_asgn: primary_value "::" "local variable or method" tOP_ASGN command_rhs */
+#line 2366 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_op_asgn(p, new_call(p, (yyvsp[-4].nd), (yyvsp[-2].id), 0, tCOLON2), (yyvsp[-1].id), (yyvsp[0].nd));
+ }
+#line 7721 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 40: /* command_asgn: defn_head f_opt_arglist_paren '=' command */
+#line 2370 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-3].nd);
+ endless_method_name(p, (yyvsp[-3].nd));
+ void_expr_error(p, (yyvsp[0].nd));
+ defn_setup(p, (yyval.nd), (yyvsp[-2].nd), (yyvsp[0].nd));
+ nvars_unnest(p);
+ p->in_def--;
+ }
+#line 7734 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 41: /* command_asgn: defn_head f_opt_arglist_paren '=' command "'rescue' modifier" arg */
+#line 2379 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-5].nd);
+ endless_method_name(p, (yyvsp[-5].nd));
+ void_expr_error(p, (yyvsp[-2].nd));
+ defn_setup(p, (yyval.nd), (yyvsp[-4].nd), new_mod_rescue(p, (yyvsp[-2].nd), (yyvsp[0].nd)));
+ nvars_unnest(p);
+ p->in_def--;
+ }
+#line 7747 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 42: /* command_asgn: defs_head f_opt_arglist_paren '=' command */
+#line 2388 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-3].nd);
+ void_expr_error(p, (yyvsp[0].nd));
+ defn_setup(p, (yyval.nd), (yyvsp[-2].nd), (yyvsp[0].nd));
+ nvars_unnest(p);
+ p->in_def--;
+ p->in_single--;
+ }
+#line 7760 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 43: /* command_asgn: defs_head f_opt_arglist_paren '=' command "'rescue' modifier" arg */
+#line 2397 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-5].nd);
+ void_expr_error(p, (yyvsp[-2].nd));
+ defn_setup(p, (yyval.nd), (yyvsp[-4].nd), new_mod_rescue(p, (yyvsp[-2].nd), (yyvsp[0].nd)));
+ nvars_unnest(p);
+ p->in_def--;
+ p->in_single--;
+ }
+#line 7773 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 44: /* command_asgn: backref tOP_ASGN command_rhs */
+#line 2406 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ backref_error(p, (yyvsp[-2].nd));
+ (yyval.nd) = new_stmts(p, 0);
+ }
+#line 7782 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 46: /* command_rhs: command_call "'rescue' modifier" stmt */
+#line 2414 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_mod_rescue(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 7790 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 49: /* expr: expr "'and'" expr */
+#line 2422 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_and(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 7798 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 50: /* expr: expr "'or'" expr */
+#line 2426 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_or(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 7806 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 51: /* expr: "'not'" opt_nl expr */
+#line 2430 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_uni_op(p, cond((yyvsp[0].nd)), "!");
+ }
+#line 7814 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 52: /* expr: '!' command_call */
+#line 2434 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_uni_op(p, cond((yyvsp[0].nd)), "!");
+ }
+#line 7822 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 53: /* $@4: %empty */
+#line 2437 "mrbgems/mruby-compiler/core/parse.y"
+ {p->in_kwarg++;}
+#line 7828 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 54: /* expr: arg "=>" $@4 p_expr */
+#line 2438 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* expr => pattern (raises NoMatchingPatternError on failure) */
+ p->in_kwarg--;
+ (yyval.nd) = new_match_pat(p, (yyvsp[-3].nd), (yyvsp[0].nd), TRUE);
+ }
+#line 7838 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 55: /* $@5: %empty */
+#line 2443 "mrbgems/mruby-compiler/core/parse.y"
+ {p->in_kwarg++;}
+#line 7844 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 56: /* expr: arg "'in'" $@5 p_expr */
+#line 2444 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* expr in pattern (returns true/false) */
+ p->in_kwarg--;
+ (yyval.nd) = new_match_pat(p, (yyvsp[-3].nd), (yyvsp[0].nd), FALSE);
+ }
+#line 7854 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 58: /* defn_head: "'def'" fname */
+#line 2453 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_def(p, (yyvsp[0].id));
+ p->cmdarg_stack = 0;
+ p->in_def++;
+ nvars_block(p);
+ }
+#line 7865 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 59: /* $@6: %empty */
+#line 2462 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ p->lstate = EXPR_FNAME;
+ }
+#line 7873 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 60: /* defs_head: "'def'" singleton dot_or_colon $@6 fname */
+#line 2466 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_sdef(p, (yyvsp[-3].nd), (yyvsp[0].id));
+ p->cmdarg_stack = 0;
+ p->in_def++;
+ p->in_single++;
+ nvars_block(p);
+ p->lstate = EXPR_ENDFN; /* force for args */
+ }
+#line 7886 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 61: /* expr_value: expr */
+#line 2477 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ if (!(yyvsp[0].nd)) (yyval.nd) = new_nil(p);
+ else {
+ (yyval.nd) = (yyvsp[0].nd);
+ }
+ }
+#line 7897 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 65: /* block_command: block_call call_op2 operation2 command_args */
+#line 2491 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-3].nd), (yyvsp[-1].id), (yyvsp[0].nd), (yyvsp[-2].num));
+ }
+#line 7905 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 66: /* $@7: %empty */
+#line 2497 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_nest(p);
+ nvars_nest(p);
+ }
+#line 7914 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 67: /* cmd_brace_block: "{" $@7 opt_block_param compstmt '}' */
+#line 2504 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_block(p, (yyvsp[-2].nd), (yyvsp[-1].nd));
+ local_unnest(p);
+ nvars_unnest(p);
+ }
+#line 7924 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 68: /* command: operation command_args */
+#line 2512 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_fcall(p, (yyvsp[-1].id), (yyvsp[0].nd));
+ }
+#line 7932 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 69: /* command: operation command_args cmd_brace_block */
+#line 2516 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ args_with_block(p, (yyvsp[-1].nd), (yyvsp[0].nd));
+ (yyval.nd) = new_fcall(p, (yyvsp[-2].id), (yyvsp[-1].nd));
+ }
+#line 7941 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 70: /* command: primary_value call_op operation2 command_args */
+#line 2521 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-3].nd), (yyvsp[-1].id), (yyvsp[0].nd), (yyvsp[-2].num));
+ }
+#line 7949 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 71: /* command: primary_value call_op operation2 command_args cmd_brace_block */
+#line 2525 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ args_with_block(p, (yyvsp[-1].nd), (yyvsp[0].nd));
+ (yyval.nd) = new_call(p, (yyvsp[-4].nd), (yyvsp[-2].id), (yyvsp[-1].nd), (yyvsp[-3].num));
+ }
+#line 7958 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 72: /* command: primary_value "::" operation2 command_args */
+#line 2530 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-3].nd), (yyvsp[-1].id), (yyvsp[0].nd), tCOLON2);
+ }
+#line 7966 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 73: /* command: primary_value "::" operation2 command_args cmd_brace_block */
+#line 2534 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ args_with_block(p, (yyvsp[-1].nd), (yyvsp[0].nd));
+ (yyval.nd) = new_call(p, (yyvsp[-4].nd), (yyvsp[-2].id), (yyvsp[-1].nd), tCOLON2);
+ }
+#line 7975 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 74: /* command: "'super'" command_args */
+#line 2539 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_super(p, (yyvsp[0].nd));
+ }
+#line 7983 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 75: /* command: "'yield'" command_args */
+#line 2543 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_yield(p, (yyvsp[0].nd));
+ }
+#line 7991 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 76: /* command: "'return'" call_args */
+#line 2547 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_return(p, ret_args(p, (yyvsp[0].nd)));
+ }
+#line 7999 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 77: /* command: "'break'" call_args */
+#line 2551 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_break(p, ret_args(p, (yyvsp[0].nd)));
+ }
+#line 8007 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 78: /* command: "'next'" call_args */
+#line 2555 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_next(p, ret_args(p, (yyvsp[0].nd)));
+ }
+#line 8015 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 79: /* mlhs: mlhs_basic */
+#line 2561 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[0].nd);
+ }
+#line 8023 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 80: /* mlhs: tLPAREN mlhs_inner rparen */
+#line 2565 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 8031 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 82: /* mlhs_inner: tLPAREN mlhs_inner rparen */
+#line 2572 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 8039 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 83: /* mlhs_basic: mlhs_list */
+#line 2578 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 8047 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 84: /* mlhs_basic: mlhs_list mlhs_item */
+#line 2582 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1(push((yyvsp[-1].nd),(yyvsp[0].nd)));
+ }
+#line 8055 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 85: /* mlhs_basic: mlhs_list "*" mlhs_node */
+#line 2586 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list2((yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 8063 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 86: /* mlhs_basic: mlhs_list "*" mlhs_node ',' mlhs_post */
+#line 2590 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list3((yyvsp[-4].nd), (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 8071 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 87: /* mlhs_basic: mlhs_list "*" */
+#line 2594 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list2((yyvsp[-1].nd), new_nil(p));
+ }
+#line 8079 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 88: /* mlhs_basic: mlhs_list "*" ',' mlhs_post */
+#line 2598 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list3((yyvsp[-3].nd), new_nil(p), (yyvsp[0].nd));
+ }
+#line 8087 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 89: /* mlhs_basic: "*" mlhs_node */
+#line 2602 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list2(0, (yyvsp[0].nd));
+ }
+#line 8095 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 90: /* mlhs_basic: "*" mlhs_node ',' mlhs_post */
+#line 2606 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list3(0, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 8103 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 91: /* mlhs_basic: "*" */
+#line 2610 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list2(0, new_nil(p));
+ }
+#line 8111 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 92: /* mlhs_basic: "*" ',' mlhs_post */
+#line 2614 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list3(0, new_nil(p), (yyvsp[0].nd));
+ }
+#line 8119 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 94: /* mlhs_item: tLPAREN mlhs_inner rparen */
+#line 2621 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_masgn(p, (yyvsp[-1].nd), NULL);
+ }
+#line 8127 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 95: /* mlhs_list: mlhs_item ',' */
+#line 2627 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1((yyvsp[-1].nd));
+ }
+#line 8135 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 96: /* mlhs_list: mlhs_list mlhs_item ',' */
+#line 2631 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-2].nd), (yyvsp[-1].nd));
+ }
+#line 8143 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 97: /* mlhs_post: mlhs_item */
+#line 2637 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 8151 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 98: /* mlhs_post: mlhs_list mlhs_item */
+#line 2641 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 8159 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 99: /* mlhs_node: variable */
+#line 2647 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ assignable(p, (yyvsp[0].nd));
+ }
+#line 8167 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 100: /* mlhs_node: primary_value '[' opt_call_args ']' */
+#line 2651 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-3].nd), intern_op(aref), (yyvsp[-1].nd), '.');
+ }
+#line 8175 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 101: /* mlhs_node: primary_value call_op "local variable or method" */
+#line 2655 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-2].nd), (yyvsp[0].id), 0, (yyvsp[-1].num));
+ }
+#line 8183 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 102: /* mlhs_node: primary_value "::" "local variable or method" */
+#line 2659 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-2].nd), (yyvsp[0].id), 0, tCOLON2);
+ }
+#line 8191 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 103: /* mlhs_node: primary_value call_op "constant" */
+#line 2663 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-2].nd), (yyvsp[0].id), 0, (yyvsp[-1].num));
+ }
+#line 8199 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 104: /* mlhs_node: primary_value "::" "constant" */
+#line 2667 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ if (p->in_def || p->in_single)
+ yyerror(&(yylsp[-2]), p, "dynamic constant assignment");
+ (yyval.nd) = new_colon2(p, (yyvsp[-2].nd), (yyvsp[0].id));
+ }
+#line 8209 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 105: /* mlhs_node: tCOLON3 "constant" */
+#line 2673 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ if (p->in_def || p->in_single)
+ yyerror(&(yylsp[-1]), p, "dynamic constant assignment");
+ (yyval.nd) = new_colon3(p, (yyvsp[0].id));
+ }
+#line 8219 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 106: /* mlhs_node: backref */
+#line 2679 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ backref_error(p, (yyvsp[0].nd));
+ (yyval.nd) = 0;
+ }
+#line 8228 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 107: /* lhs: variable */
+#line 2686 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ assignable(p, (yyvsp[0].nd));
+ }
+#line 8236 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 108: /* lhs: primary_value '[' opt_call_args ']' */
+#line 2690 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-3].nd), intern_op(aref), (yyvsp[-1].nd), '.');
+ }
+#line 8244 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 109: /* lhs: primary_value call_op "local variable or method" */
+#line 2694 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-2].nd), (yyvsp[0].id), 0, (yyvsp[-1].num));
+ }
+#line 8252 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 110: /* lhs: primary_value "::" "local variable or method" */
+#line 2698 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-2].nd), (yyvsp[0].id), 0, tCOLON2);
+ }
+#line 8260 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 111: /* lhs: primary_value call_op "constant" */
+#line 2702 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-2].nd), (yyvsp[0].id), 0, (yyvsp[-1].num));
+ }
+#line 8268 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 112: /* lhs: primary_value "::" "constant" */
+#line 2706 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ if (p->in_def || p->in_single)
+ yyerror(&(yylsp[-2]), p, "dynamic constant assignment");
+ (yyval.nd) = new_colon2(p, (yyvsp[-2].nd), (yyvsp[0].id));
+ }
+#line 8278 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 113: /* lhs: tCOLON3 "constant" */
+#line 2712 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ if (p->in_def || p->in_single)
+ yyerror(&(yylsp[-1]), p, "dynamic constant assignment");
+ (yyval.nd) = new_colon3(p, (yyvsp[0].id));
+ }
+#line 8288 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 114: /* lhs: backref */
+#line 2718 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ backref_error(p, (yyvsp[0].nd));
+ (yyval.nd) = 0;
+ }
+#line 8297 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 115: /* lhs: "numbered parameter" */
+#line 2723 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ yyerror(&(yylsp[0]), p, "can't assign to numbered parameter");
+ }
+#line 8305 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 116: /* cname: "local variable or method" */
+#line 2729 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ yyerror(&(yylsp[0]), p, "class/module name must be CONSTANT");
+ }
+#line 8313 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 118: /* cpath: tCOLON3 cname */
+#line 2736 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = cons(int_to_node(1), sym_to_node((yyvsp[0].id)));
+ }
+#line 8321 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 119: /* cpath: cname */
+#line 2740 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = cons(int_to_node(0), sym_to_node((yyvsp[0].id)));
+ }
+#line 8329 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 120: /* cpath: primary_value "::" cname */
+#line 2744 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[-2].nd));
+ (yyval.nd) = cons((yyvsp[-2].nd), sym_to_node((yyvsp[0].id)));
+ }
+#line 8338 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 124: /* fname: op */
+#line 2754 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ p->lstate = EXPR_ENDFN;
+ (yyval.id) = (yyvsp[0].id);
+ }
+#line 8347 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 125: /* fname: reswords */
+#line 2759 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ p->lstate = EXPR_ENDFN;
+ (yyval.id) = (yyvsp[0].id);
+ }
+#line 8356 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 128: /* undef_list: fsym */
+#line 2770 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = cons(sym_to_node((yyvsp[0].id)), 0);
+ }
+#line 8364 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 129: /* $@8: %empty */
+#line 2773 "mrbgems/mruby-compiler/core/parse.y"
+ {p->lstate = EXPR_FNAME;}
+#line 8370 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 130: /* undef_list: undef_list ',' $@8 fsym */
+#line 2774 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-3].nd), sym_to_node((yyvsp[0].id)));
+ }
+#line 8378 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 131: /* op: '|' */
+#line 2779 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(or); }
+#line 8384 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 132: /* op: '^' */
+#line 2780 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(xor); }
+#line 8390 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 133: /* op: '&' */
+#line 2781 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(and); }
+#line 8396 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 134: /* op: "<=>" */
+#line 2782 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(cmp); }
+#line 8402 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 135: /* op: "==" */
+#line 2783 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(eq); }
+#line 8408 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 136: /* op: "===" */
+#line 2784 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(eqq); }
+#line 8414 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 137: /* op: "=~" */
+#line 2785 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(match); }
+#line 8420 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 138: /* op: "!~" */
+#line 2786 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(nmatch); }
+#line 8426 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 139: /* op: '>' */
+#line 2787 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(gt); }
+#line 8432 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 140: /* op: ">=" */
+#line 2788 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(ge); }
+#line 8438 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 141: /* op: '<' */
+#line 2789 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(lt); }
+#line 8444 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 142: /* op: "<=" */
+#line 2790 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(le); }
+#line 8450 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 143: /* op: "!=" */
+#line 2791 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(neq); }
+#line 8456 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 144: /* op: "<<" */
+#line 2792 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(lshift); }
+#line 8462 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 145: /* op: ">>" */
+#line 2793 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(rshift); }
+#line 8468 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 146: /* op: '+' */
+#line 2794 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(add); }
+#line 8474 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 147: /* op: '-' */
+#line 2795 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(sub); }
+#line 8480 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 148: /* op: '*' */
+#line 2796 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(mul); }
+#line 8486 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 149: /* op: "*" */
+#line 2797 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(mul); }
+#line 8492 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 150: /* op: '/' */
+#line 2798 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(div); }
+#line 8498 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 151: /* op: '%' */
+#line 2799 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(mod); }
+#line 8504 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 152: /* op: tPOW */
+#line 2800 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(pow); }
+#line 8510 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 153: /* op: "**" */
+#line 2801 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(pow); }
+#line 8516 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 154: /* op: '!' */
+#line 2802 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(not); }
+#line 8522 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 155: /* op: '~' */
+#line 2803 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(neg); }
+#line 8528 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 156: /* op: "unary plus" */
+#line 2804 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(plus); }
+#line 8534 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 157: /* op: "unary minus" */
+#line 2805 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(minus); }
+#line 8540 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 158: /* op: tAREF */
+#line 2806 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(aref); }
+#line 8546 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 159: /* op: tASET */
+#line 2807 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(aset); }
+#line 8552 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 160: /* op: '`' */
+#line 2808 "mrbgems/mruby-compiler/core/parse.y"
+ { (yyval.id) = intern_op(tick); }
+#line 8558 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 201: /* arg: lhs '=' arg_rhs */
+#line 2826 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_asgn(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 8566 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 202: /* arg: var_lhs tOP_ASGN arg_rhs */
+#line 2830 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_op_asgn(p, (yyvsp[-2].nd), (yyvsp[-1].id), (yyvsp[0].nd));
+ }
+#line 8574 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 203: /* arg: primary_value '[' opt_call_args ']' tOP_ASGN arg_rhs */
+#line 2834 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_op_asgn(p, new_call(p, (yyvsp[-5].nd), intern_op(aref), (yyvsp[-3].nd), '.'), (yyvsp[-1].id), (yyvsp[0].nd));
+ }
+#line 8582 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 204: /* arg: primary_value call_op "local variable or method" tOP_ASGN arg_rhs */
+#line 2838 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_op_asgn(p, new_call(p, (yyvsp[-4].nd), (yyvsp[-2].id), 0, (yyvsp[-3].num)), (yyvsp[-1].id), (yyvsp[0].nd));
+ }
+#line 8590 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 205: /* arg: primary_value call_op "constant" tOP_ASGN arg_rhs */
+#line 2842 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_op_asgn(p, new_call(p, (yyvsp[-4].nd), (yyvsp[-2].id), 0, (yyvsp[-3].num)), (yyvsp[-1].id), (yyvsp[0].nd));
+ }
+#line 8598 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 206: /* arg: primary_value "::" "local variable or method" tOP_ASGN arg_rhs */
+#line 2846 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_op_asgn(p, new_call(p, (yyvsp[-4].nd), (yyvsp[-2].id), 0, tCOLON2), (yyvsp[-1].id), (yyvsp[0].nd));
+ }
+#line 8606 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 207: /* arg: primary_value "::" "constant" tOP_ASGN arg_rhs */
+#line 2850 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ yyerror(&(yylsp[-4]), p, "constant re-assignment");
+ (yyval.nd) = new_stmts(p, 0);
+ }
+#line 8615 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 208: /* arg: tCOLON3 "constant" tOP_ASGN arg_rhs */
+#line 2855 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ yyerror(&(yylsp[-3]), p, "constant re-assignment");
+ (yyval.nd) = new_stmts(p, 0);
+ }
+#line 8624 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 209: /* arg: backref tOP_ASGN arg_rhs */
+#line 2860 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ backref_error(p, (yyvsp[-2].nd));
+ (yyval.nd) = new_stmts(p, 0);
+ }
+#line 8633 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 210: /* arg: arg ".." arg */
+#line 2865 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_dot2(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 8641 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 211: /* arg: arg ".." */
+#line 2869 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_dot2(p, (yyvsp[-1].nd), new_nil(p));
+ }
+#line 8649 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 212: /* arg: tBDOT2 arg */
+#line 2873 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_dot2(p, new_nil(p), (yyvsp[0].nd));
+ }
+#line 8657 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 213: /* arg: arg "..." arg */
+#line 2877 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_dot3(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 8665 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 214: /* arg: arg "..." */
+#line 2881 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_dot3(p, (yyvsp[-1].nd), new_nil(p));
+ }
+#line 8673 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 215: /* arg: tBDOT3 arg */
+#line 2885 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_dot3(p, new_nil(p), (yyvsp[0].nd));
+ }
+#line 8681 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 216: /* arg: arg '+' arg */
+#line 2889 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "+", (yyvsp[0].nd));
+ }
+#line 8689 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 217: /* arg: arg '-' arg */
+#line 2893 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "-", (yyvsp[0].nd));
+ }
+#line 8697 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 218: /* arg: arg '*' arg */
+#line 2897 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "*", (yyvsp[0].nd));
+ }
+#line 8705 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 219: /* arg: arg '/' arg */
+#line 2901 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "/", (yyvsp[0].nd));
+ }
+#line 8713 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 220: /* arg: arg '%' arg */
+#line 2905 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "%", (yyvsp[0].nd));
+ }
+#line 8721 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 221: /* arg: arg tPOW arg */
+#line 2909 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "**", (yyvsp[0].nd));
+ }
+#line 8729 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 222: /* arg: tUMINUS_NUM "integer literal" tPOW arg */
+#line 2913 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_negate(p, call_bin_op(p, (yyvsp[-2].nd), "**", (yyvsp[0].nd)));
+ }
+#line 8737 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 223: /* arg: tUMINUS_NUM "float literal" tPOW arg */
+#line 2917 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_negate(p, call_bin_op(p, (yyvsp[-2].nd), "**", (yyvsp[0].nd)));
+ }
+#line 8745 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 224: /* arg: "unary plus" arg */
+#line 2921 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_uni_op(p, (yyvsp[0].nd), "+@");
+ }
+#line 8753 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 225: /* arg: "unary minus" arg */
+#line 2925 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_negate(p, (yyvsp[0].nd));
+ }
+#line 8761 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 226: /* arg: arg '|' arg */
+#line 2929 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "|", (yyvsp[0].nd));
+ }
+#line 8769 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 227: /* arg: arg '^' arg */
+#line 2933 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "^", (yyvsp[0].nd));
+ }
+#line 8777 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 228: /* arg: arg '&' arg */
+#line 2937 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "&", (yyvsp[0].nd));
+ }
+#line 8785 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 229: /* arg: arg "<=>" arg */
+#line 2941 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "<=>", (yyvsp[0].nd));
+ }
+#line 8793 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 230: /* arg: arg '>' arg */
+#line 2945 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), ">", (yyvsp[0].nd));
+ }
+#line 8801 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 231: /* arg: arg ">=" arg */
+#line 2949 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), ">=", (yyvsp[0].nd));
+ }
+#line 8809 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 232: /* arg: arg '<' arg */
+#line 2953 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "<", (yyvsp[0].nd));
+ }
+#line 8817 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 233: /* arg: arg "<=" arg */
+#line 2957 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "<=", (yyvsp[0].nd));
+ }
+#line 8825 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 234: /* arg: arg "==" arg */
+#line 2961 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "==", (yyvsp[0].nd));
+ }
+#line 8833 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 235: /* arg: arg "===" arg */
+#line 2965 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "===", (yyvsp[0].nd));
+ }
+#line 8841 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 236: /* arg: arg "!=" arg */
+#line 2969 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "!=", (yyvsp[0].nd));
+ }
+#line 8849 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 237: /* arg: arg "=~" arg */
+#line 2973 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "=~", (yyvsp[0].nd));
+ }
+#line 8857 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 238: /* arg: arg "!~" arg */
+#line 2977 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "!~", (yyvsp[0].nd));
+ }
+#line 8865 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 239: /* arg: '!' arg */
+#line 2981 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_uni_op(p, cond((yyvsp[0].nd)), "!");
+ }
+#line 8873 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 240: /* arg: '~' arg */
+#line 2985 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_uni_op(p, cond((yyvsp[0].nd)), "~");
+ }
+#line 8881 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 241: /* arg: arg "<<" arg */
+#line 2989 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), "<<", (yyvsp[0].nd));
+ }
+#line 8889 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 242: /* arg: arg ">>" arg */
+#line 2993 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_bin_op(p, (yyvsp[-2].nd), ">>", (yyvsp[0].nd));
+ }
+#line 8897 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 243: /* arg: arg "&&" arg */
+#line 2997 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_and(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 8905 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 244: /* arg: arg "||" arg */
+#line 3001 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_or(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 8913 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 245: /* arg: arg '?' arg opt_nl ':' arg */
+#line 3005 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_if(p, cond((yyvsp[-5].nd)), (yyvsp[-3].nd), (yyvsp[0].nd));
+ }
+#line 8921 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 246: /* arg: arg '?' arg opt_nl "label" arg */
+#line 3009 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_if(p, cond((yyvsp[-5].nd)), (yyvsp[-3].nd), (yyvsp[0].nd));
+ }
+#line 8929 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 247: /* arg: defn_head f_opt_arglist_paren '=' arg */
+#line 3013 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-3].nd);
+ endless_method_name(p, (yyvsp[-3].nd));
+ void_expr_error(p, (yyvsp[0].nd));
+ defn_setup(p, (yyval.nd), (yyvsp[-2].nd), (yyvsp[0].nd));
+ nvars_unnest(p);
+ p->in_def--;
+ }
+#line 8942 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 248: /* arg: defn_head f_opt_arglist_paren '=' arg "'rescue' modifier" arg */
+#line 3022 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-5].nd);
+ endless_method_name(p, (yyvsp[-5].nd));
+ void_expr_error(p, (yyvsp[-2].nd));
+ defn_setup(p, (yyval.nd), (yyvsp[-4].nd), new_mod_rescue(p, (yyvsp[-2].nd), (yyvsp[0].nd)));
+ nvars_unnest(p);
+ p->in_def--;
+ }
+#line 8955 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 249: /* arg: defs_head f_opt_arglist_paren '=' arg */
+#line 3031 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-3].nd);
+ void_expr_error(p, (yyvsp[0].nd));
+ defn_setup(p, (yyval.nd), (yyvsp[-2].nd), (yyvsp[0].nd));
+ nvars_unnest(p);
+ p->in_def--;
+ p->in_single--;
+ }
+#line 8968 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 250: /* arg: defs_head f_opt_arglist_paren '=' arg "'rescue' modifier" arg */
+#line 3040 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-5].nd);
+ void_expr_error(p, (yyvsp[-2].nd));
+ defn_setup(p, (yyval.nd), (yyvsp[-4].nd), new_mod_rescue(p, (yyvsp[-2].nd), (yyvsp[0].nd)));
+ nvars_unnest(p);
+ p->in_def--;
+ p->in_single--;
+ }
+#line 8981 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 251: /* arg: primary */
+#line 3049 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[0].nd);
+ }
+#line 8989 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 253: /* aref_args: args trailer */
+#line 3056 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 8997 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 254: /* aref_args: args comma assocs trailer */
+#line 3060 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-3].nd), new_hash(p, (yyvsp[-1].nd)));
+ }
+#line 9005 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 255: /* aref_args: assocs trailer */
+#line 3064 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = cons(new_hash(p, (yyvsp[-1].nd)), 0);
+ }
+#line 9013 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 256: /* arg_rhs: arg */
+#line 3070 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[0].nd);
+ }
+#line 9021 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 257: /* arg_rhs: arg "'rescue' modifier" arg */
+#line 3074 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[-2].nd));
+ (yyval.nd) = new_mod_rescue(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 9030 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 258: /* paren_args: '(' opt_call_args ')' */
+#line 3081 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 9038 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 259: /* paren_args: '(' args comma tBDOT3 rparen */
+#line 3085 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ mrb_sym r = intern_op(mul);
+ mrb_sym k = intern_op(pow);
+ mrb_sym b = intern_op(and);
+ (yyval.nd) = new_callargs(p, push((yyvsp[-3].nd), new_splat(p, new_lvar(p, r))),
+ list1(cons(new_kw_rest_args(p, 0), new_lvar(p, k))),
+ new_block_arg(p, new_lvar(p, b)));
+ }
+#line 9051 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 260: /* paren_args: '(' tBDOT3 rparen */
+#line 3094 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ mrb_sym r = intern_op(mul);
+ mrb_sym k = intern_op(pow);
+ mrb_sym b = intern_op(and);
+ if (local_var_p(p, r) && local_var_p(p, k) && local_var_p(p, b)) {
+ (yyval.nd) = new_callargs(p, list1(new_splat(p, new_lvar(p, r))),
+ list1(cons(new_kw_rest_args(p, 0), new_lvar(p, k))),
+ new_block_arg(p, new_lvar(p, b)));
+ }
+ else {
+ yyerror(&(yylsp[-2]), p, "unexpected argument forwarding ...");
+ (yyval.nd) = 0;
+ }
+ }
+#line 9070 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 265: /* opt_call_args: args comma */
+#line 3117 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_callargs(p,(yyvsp[-1].nd),0,0);
+ }
+#line 9078 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 266: /* opt_call_args: args comma assocs comma */
+#line 3121 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_callargs(p,(yyvsp[-3].nd),(yyvsp[-1].nd),0);
+ }
+#line 9086 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 267: /* opt_call_args: assocs comma */
+#line 3125 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_callargs(p,0,(yyvsp[-1].nd),0);
+ }
+#line 9094 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 268: /* call_args: command */
+#line 3131 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[0].nd));
+ (yyval.nd) = new_callargs(p, list1((yyvsp[0].nd)), 0, 0);
+ }
+#line 9103 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 269: /* call_args: args opt_block_arg */
+#line 3136 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_callargs(p, (yyvsp[-1].nd), 0, (yyvsp[0].nd));
+ }
+#line 9111 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 270: /* call_args: assocs opt_block_arg */
+#line 3140 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_callargs(p, 0, (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 9119 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 271: /* call_args: args comma assocs opt_block_arg */
+#line 3144 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_callargs(p, (yyvsp[-3].nd), (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 9127 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 272: /* call_args: block_arg */
+#line 3148 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_callargs(p, 0, 0, (yyvsp[0].nd));
+ }
+#line 9135 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 273: /* @9: %empty */
+#line 3153 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.stack) = p->cmdarg_stack;
+ CMDARG_PUSH(1);
+ }
+#line 9144 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 274: /* command_args: @9 call_args */
+#line 3158 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ p->cmdarg_stack = (yyvsp[-1].stack);
+ (yyval.nd) = (yyvsp[0].nd);
+ }
+#line 9153 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 275: /* block_arg: "&" arg */
+#line 3165 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_block_arg(p, (yyvsp[0].nd));
+ }
+#line 9161 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 276: /* block_arg: "&" */
+#line 3169 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_block_arg(p, 0);
+ }
+#line 9169 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 277: /* opt_block_arg: comma block_arg */
+#line 3175 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[0].nd);
+ }
+#line 9177 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 278: /* opt_block_arg: none */
+#line 3179 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = 0;
+ }
+#line 9185 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 280: /* args: arg */
+#line 3188 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[0].nd));
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 9194 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 281: /* args: "*" */
+#line 3193 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1(new_splat(p, new_lvar(p, intern_op(mul))));
+ }
+#line 9202 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 282: /* args: "*" arg */
+#line 3197 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1(new_splat(p, (yyvsp[0].nd)));
+ }
+#line 9210 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 283: /* args: args comma arg */
+#line 3201 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[0].nd));
+ (yyval.nd) = push((yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 9219 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 284: /* args: args comma "*" */
+#line 3206 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-2].nd), new_splat(p, new_lvar(p, intern_op(mul))));
+ }
+#line 9227 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 285: /* args: args comma "*" arg */
+#line 3210 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-3].nd), new_splat(p, (yyvsp[0].nd)));
+ }
+#line 9235 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 286: /* mrhs: args comma arg */
+#line 3216 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[0].nd));
+ (yyval.nd) = push((yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 9244 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 287: /* mrhs: args comma "*" arg */
+#line 3221 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-3].nd), new_splat(p, (yyvsp[0].nd)));
+ }
+#line 9252 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 288: /* mrhs: "*" arg */
+#line 3225 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1(new_splat(p, (yyvsp[0].nd)));
+ }
+#line 9260 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 290: /* primary: string */
+#line 3232 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_str(p, (yyvsp[0].nd));
+ }
+#line 9268 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 291: /* primary: xstring */
+#line 3236 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_xstr(p, (yyvsp[0].nd));
+ }
+#line 9276 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 296: /* primary: "method" */
+#line 3244 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_fcall(p, (yyvsp[0].id), 0);
+ }
+#line 9284 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 297: /* @10: %empty */
+#line 3248 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.stack) = p->cmdarg_stack;
+ p->cmdarg_stack = 0;
+ }
+#line 9293 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 298: /* primary: "'begin'" @10 bodystmt "'end'" */
+#line 3254 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ p->cmdarg_stack = (yyvsp[-2].stack);
+ (yyval.nd) = new_begin(p, (yyvsp[-1].nd));
+ }
+#line 9302 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 299: /* @11: %empty */
+#line 3259 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.stack) = p->cmdarg_stack;
+ p->cmdarg_stack = 0;
+ }
+#line 9311 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 300: /* $@12: %empty */
+#line 3263 "mrbgems/mruby-compiler/core/parse.y"
+ {p->lstate = EXPR_ENDARG;}
+#line 9317 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 301: /* primary: "(" @11 compstmt $@12 rparen */
+#line 3264 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ p->cmdarg_stack = (yyvsp[-3].stack);
+ (yyval.nd) = (yyvsp[-2].nd);
+ }
+#line 9326 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 302: /* $@13: %empty */
+#line 3268 "mrbgems/mruby-compiler/core/parse.y"
+ {p->lstate = EXPR_ENDARG;}
+#line 9332 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 303: /* primary: "(" $@13 rparen */
+#line 3269 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_nil(p);
+ }
+#line 9340 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 304: /* primary: tLPAREN compstmt ')' */
+#line 3273 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 9348 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 305: /* primary: primary_value "::" "constant" */
+#line 3277 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_colon2(p, (yyvsp[-2].nd), (yyvsp[0].id));
+ }
+#line 9356 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 306: /* primary: tCOLON3 "constant" */
+#line 3281 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_colon3(p, (yyvsp[0].id));
+ }
+#line 9364 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 307: /* primary: "[" aref_args ']' */
+#line 3285 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_array(p, (yyvsp[-1].nd));
+ }
+#line 9372 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 308: /* primary: tLBRACE assoc_list '}' */
+#line 3289 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_hash(p, (yyvsp[-1].nd));
+ }
+#line 9380 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 309: /* primary: "'return'" */
+#line 3293 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_return(p, 0);
+ }
+#line 9388 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 310: /* primary: "'yield'" opt_paren_args */
+#line 3297 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_yield(p, (yyvsp[0].nd));
+ }
+#line 9396 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 311: /* primary: "'not'" '(' expr rparen */
+#line 3301 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_uni_op(p, cond((yyvsp[-1].nd)), "!");
+ }
+#line 9404 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 312: /* primary: "'not'" '(' rparen */
+#line 3305 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = call_uni_op(p, new_nil(p), "!");
+ }
+#line 9412 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 313: /* primary: operation brace_block */
+#line 3309 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_fcall(p, (yyvsp[-1].id), new_callargs(p, 0, 0, (yyvsp[0].nd)));
+ }
+#line 9420 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 315: /* primary: method_call brace_block */
+#line 3314 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ call_with_block(p, (yyvsp[-1].nd), (yyvsp[0].nd));
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 9429 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 316: /* @14: %empty */
+#line 3319 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_nest(p);
+ nvars_nest(p);
+ (yyval.num) = p->lpar_beg;
+ p->lpar_beg = ++p->paren_nest;
+ }
+#line 9440 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 317: /* @15: %empty */
+#line 3326 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.stack) = p->cmdarg_stack;
+ p->cmdarg_stack = 0;
+ }
+#line 9449 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 318: /* primary: "->" @14 f_larglist @15 lambda_body */
+#line 3331 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ p->lpar_beg = (yyvsp[-3].num);
+ (yyval.nd) = new_lambda(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ local_unnest(p);
+ nvars_unnest(p);
+ p->cmdarg_stack = (yyvsp[-1].stack);
+ CMDARG_LEXPOP();
+ }
+#line 9462 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 319: /* primary: "'if'" expr_value then compstmt if_tail "'end'" */
+#line 3343 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_if(p, cond((yyvsp[-4].nd)), (yyvsp[-2].nd), (yyvsp[-1].nd));
+ SET_LINENO((yyval.nd), (yyvsp[-5].num));
+ }
+#line 9471 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 320: /* primary: "'unless'" expr_value then compstmt opt_else "'end'" */
+#line 3351 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_if(p, cond((yyvsp[-4].nd)), (yyvsp[-1].nd), (yyvsp[-2].nd));
+ SET_LINENO((yyval.nd), (yyvsp[-5].num));
+ }
+#line 9480 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 321: /* $@16: %empty */
+#line 3355 "mrbgems/mruby-compiler/core/parse.y"
+ {COND_PUSH(1);}
+#line 9486 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 322: /* $@17: %empty */
+#line 3355 "mrbgems/mruby-compiler/core/parse.y"
+ {COND_POP();}
+#line 9492 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 323: /* primary: "'while'" $@16 expr_value do $@17 compstmt "'end'" */
+#line 3358 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_while(p, cond((yyvsp[-4].nd)), (yyvsp[-1].nd));
+ SET_LINENO((yyval.nd), (yyvsp[-6].num));
+ }
+#line 9501 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 324: /* $@18: %empty */
+#line 3362 "mrbgems/mruby-compiler/core/parse.y"
+ {COND_PUSH(1);}
+#line 9507 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 325: /* $@19: %empty */
+#line 3362 "mrbgems/mruby-compiler/core/parse.y"
+ {COND_POP();}
+#line 9513 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 326: /* primary: "'until'" $@18 expr_value do $@19 compstmt "'end'" */
+#line 3365 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_until(p, cond((yyvsp[-4].nd)), (yyvsp[-1].nd));
+ SET_LINENO((yyval.nd), (yyvsp[-6].num));
+ }
+#line 9522 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 327: /* primary: "'case'" expr_value opt_terms case_body "'end'" */
+#line 3372 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_case(p, (yyvsp[-3].nd), (yyvsp[-1].nd));
+ }
+#line 9530 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 328: /* primary: "'case'" opt_terms case_body "'end'" */
+#line 3376 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_case(p, 0, (yyvsp[-1].nd));
+ }
+#line 9538 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 329: /* primary: "'case'" expr_value opt_terms "'in'" p_expr then compstmt in_clauses "'end'" */
+#line 3384 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ node *in_clause = new_in(p, (yyvsp[-4].nd), NULL, (yyvsp[-2].nd), FALSE);
+ (yyval.nd) = new_case_match(p, (yyvsp[-7].nd), cons(in_clause, (yyvsp[-1].nd)));
+ }
+#line 9547 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 330: /* primary: "'case'" expr_value opt_terms "'in'" p_expr "'if' modifier" expr_value then compstmt in_clauses "'end'" */
+#line 3393 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ node *in_clause = new_in(p, (yyvsp[-6].nd), (yyvsp[-4].nd), (yyvsp[-2].nd), FALSE);
+ (yyval.nd) = new_case_match(p, (yyvsp[-9].nd), cons(in_clause, (yyvsp[-1].nd)));
+ }
+#line 9556 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 331: /* primary: "'case'" expr_value opt_terms "'in'" p_expr "'unless' modifier" expr_value then compstmt in_clauses "'end'" */
+#line 3402 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ node *in_clause = new_in(p, (yyvsp[-6].nd), (yyvsp[-4].nd), (yyvsp[-2].nd), TRUE);
+ (yyval.nd) = new_case_match(p, (yyvsp[-9].nd), cons(in_clause, (yyvsp[-1].nd)));
+ }
+#line 9565 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 332: /* $@20: %empty */
+#line 3407 "mrbgems/mruby-compiler/core/parse.y"
+ {COND_PUSH(1);}
+#line 9571 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 333: /* $@21: %empty */
+#line 3409 "mrbgems/mruby-compiler/core/parse.y"
+ {COND_POP();}
+#line 9577 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 334: /* primary: "'for'" for_var "'in'" $@20 expr_value do $@21 compstmt "'end'" */
+#line 3412 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_for(p, (yyvsp[-7].nd), (yyvsp[-4].nd), (yyvsp[-1].nd));
+ SET_LINENO((yyval.nd), (yyvsp[-8].num));
+ }
+#line 9586 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 335: /* @22: %empty */
+#line 3418 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ if (p->in_def || p->in_single)
+ yyerror(&(yylsp[-2]), p, "class definition in method body");
+ (yyval.nd) = local_switch(p);
+ nvars_block(p);
+ }
+#line 9597 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 336: /* primary: "'class'" cpath superclass @22 bodystmt "'end'" */
+#line 3426 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_class(p, (yyvsp[-4].nd), (yyvsp[-3].nd), (yyvsp[-1].nd));
+ SET_LINENO((yyval.nd), (yyvsp[-5].num));
+ local_resume(p, (yyvsp[-2].nd));
+ nvars_unnest(p);
+ }
+#line 9608 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 337: /* @23: %empty */
+#line 3434 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.num) = p->in_def;
+ p->in_def = 0;
+ }
+#line 9617 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 338: /* @24: %empty */
+#line 3439 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = cons(local_switch(p), int_to_node(p->in_single));
+ nvars_block(p);
+ p->in_single = 0;
+ }
+#line 9627 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 339: /* primary: "'class'" "<<" expr @23 term @24 bodystmt "'end'" */
+#line 3446 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_sclass(p, (yyvsp[-5].nd), (yyvsp[-1].nd));
+ SET_LINENO((yyval.nd), (yyvsp[-7].num));
+ local_resume(p, (yyvsp[-2].nd)->car);
+ nvars_unnest(p);
+ p->in_def = (yyvsp[-4].num);
+ p->in_single = node_to_int((yyvsp[-2].nd)->cdr);
+ }
+#line 9640 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 340: /* @25: %empty */
+#line 3456 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ if (p->in_def || p->in_single)
+ yyerror(&(yylsp[-1]), p, "module definition in method body");
+ (yyval.nd) = local_switch(p);
+ nvars_block(p);
+ }
+#line 9651 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 341: /* primary: "'module'" cpath @25 bodystmt "'end'" */
+#line 3464 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_module(p, (yyvsp[-3].nd), (yyvsp[-1].nd));
+ SET_LINENO((yyval.nd), (yyvsp[-4].num));
+ local_resume(p, (yyvsp[-2].nd));
+ nvars_unnest(p);
+ }
+#line 9662 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 342: /* primary: defn_head f_arglist bodystmt "'end'" */
+#line 3474 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-3].nd);
+ defn_setup(p, (yyval.nd), (yyvsp[-2].nd), (yyvsp[-1].nd));
+ nvars_unnest(p);
+ p->in_def--;
+ }
+#line 9673 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 343: /* primary: defs_head f_arglist bodystmt "'end'" */
+#line 3484 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-3].nd);
+ defn_setup(p, (yyval.nd), (yyvsp[-2].nd), (yyvsp[-1].nd));
+ nvars_unnest(p);
+ p->in_def--;
+ p->in_single--;
+ }
+#line 9685 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 344: /* primary: "'break'" */
+#line 3492 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_break(p, 0);
+ }
+#line 9693 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 345: /* primary: "'next'" */
+#line 3496 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_next(p, 0);
+ }
+#line 9701 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 346: /* primary: "'redo'" */
+#line 3500 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_redo(p);
+ }
+#line 9709 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 347: /* primary: "'retry'" */
+#line 3504 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_retry(p);
+ }
+#line 9717 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 348: /* primary_value: primary */
+#line 3510 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[0].nd);
+ if (!(yyval.nd)) (yyval.nd) = new_nil(p);
+ }
+#line 9726 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 355: /* if_tail: "'elsif'" expr_value then compstmt if_tail */
+#line 3529 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_if(p, cond((yyvsp[-3].nd)), (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 9734 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 357: /* opt_else: "'else'" compstmt */
+#line 3536 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[0].nd);
+ }
+#line 9742 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 358: /* for_var: lhs */
+#line 3542 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1(list1((yyvsp[0].nd)));
+ }
+#line 9750 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 360: /* f_margs: f_arg */
+#line 3549 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list3((yyvsp[0].nd),0,0);
+ }
+#line 9758 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 361: /* f_margs: f_arg ',' "*" f_norm_arg */
+#line 3553 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list3((yyvsp[-3].nd), new_lvar(p, (yyvsp[0].id)), 0);
+ }
+#line 9766 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 362: /* f_margs: f_arg ',' "*" f_norm_arg ',' f_arg */
+#line 3557 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list3((yyvsp[-5].nd), new_lvar(p, (yyvsp[-2].id)), (yyvsp[0].nd));
+ }
+#line 9774 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 363: /* f_margs: f_arg ',' "*" */
+#line 3561 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_add_f(p, intern_op(mul));
+ (yyval.nd) = list3((yyvsp[-2].nd), int_to_node(-1), 0);
+ }
+#line 9783 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 364: /* f_margs: f_arg ',' "*" ',' f_arg */
+#line 3566 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list3((yyvsp[-4].nd), int_to_node(-1), (yyvsp[0].nd));
+ }
+#line 9791 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 365: /* f_margs: "*" f_norm_arg */
+#line 3570 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list3(0, new_lvar(p, (yyvsp[0].id)), 0);
+ }
+#line 9799 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 366: /* f_margs: "*" f_norm_arg ',' f_arg */
+#line 3574 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list3(0, new_lvar(p, (yyvsp[-2].id)), (yyvsp[0].nd));
+ }
+#line 9807 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 367: /* f_margs: "*" */
+#line 3578 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_add_f(p, intern_op(mul));
+ (yyval.nd) = list3(0, int_to_node(-1), 0);
+ }
+#line 9816 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 368: /* $@26: %empty */
+#line 3583 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_add_f(p, intern_op(mul));
+ }
+#line 9824 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 369: /* f_margs: "*" ',' $@26 f_arg */
+#line 3587 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list3(0, int_to_node(-1), (yyvsp[0].nd));
+ }
+#line 9832 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 370: /* block_args_tail: f_block_kwarg ',' f_kwrest opt_f_block_arg */
+#line 3593 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_tail(p, (yyvsp[-3].nd), (yyvsp[-1].id), (yyvsp[0].id));
+ }
+#line 9840 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 371: /* block_args_tail: f_block_kwarg opt_f_block_arg */
+#line 3597 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_tail(p, (yyvsp[-1].nd), 0, (yyvsp[0].id));
+ }
+#line 9848 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 372: /* block_args_tail: f_kwrest opt_f_block_arg */
+#line 3601 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_tail(p, 0, (yyvsp[-1].id), (yyvsp[0].id));
+ }
+#line 9856 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 373: /* block_args_tail: f_block_arg */
+#line 3605 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_tail(p, 0, 0, (yyvsp[0].id));
+ }
+#line 9864 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 374: /* opt_block_args_tail: ',' block_args_tail */
+#line 3611 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[0].nd);
+ }
+#line 9872 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 375: /* opt_block_args_tail: %empty */
+#line 3615 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_tail(p, 0, 0, 0);
+ }
+#line 9880 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 376: /* block_param: f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail */
+#line 3621 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-5].nd), (yyvsp[-3].nd), (yyvsp[-1].id), 0, (yyvsp[0].nd));
+ }
+#line 9888 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 377: /* block_param: f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail */
+#line 3625 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-7].nd), (yyvsp[-5].nd), (yyvsp[-3].id), (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 9896 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 378: /* block_param: f_arg ',' f_block_optarg opt_block_args_tail */
+#line 3629 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-3].nd), (yyvsp[-1].nd), 0, 0, (yyvsp[0].nd));
+ }
+#line 9904 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 379: /* block_param: f_arg ',' f_block_optarg ',' f_arg opt_block_args_tail */
+#line 3633 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-5].nd), (yyvsp[-3].nd), 0, (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 9912 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 380: /* block_param: f_arg ',' f_rest_arg opt_block_args_tail */
+#line 3637 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-3].nd), 0, (yyvsp[-1].id), 0, (yyvsp[0].nd));
+ }
+#line 9920 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 381: /* block_param: f_arg ',' opt_block_args_tail */
+#line 3641 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-2].nd), 0, 0, 0, (yyvsp[0].nd));
+ }
+#line 9928 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 382: /* block_param: f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail */
+#line 3645 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-5].nd), 0, (yyvsp[-3].id), (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 9936 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 383: /* block_param: f_arg opt_block_args_tail */
+#line 3649 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-1].nd), 0, 0, 0, (yyvsp[0].nd));
+ }
+#line 9944 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 384: /* block_param: f_block_optarg ',' f_rest_arg opt_block_args_tail */
+#line 3653 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, 0, (yyvsp[-3].nd), (yyvsp[-1].id), 0, (yyvsp[0].nd));
+ }
+#line 9952 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 385: /* block_param: f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail */
+#line 3657 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, 0, (yyvsp[-5].nd), (yyvsp[-3].id), (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 9960 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 386: /* block_param: f_block_optarg opt_block_args_tail */
+#line 3661 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, 0, (yyvsp[-1].nd), 0, 0, (yyvsp[0].nd));
+ }
+#line 9968 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 387: /* block_param: f_block_optarg ',' f_arg opt_block_args_tail */
+#line 3665 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, 0, (yyvsp[-3].nd), 0, (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 9976 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 388: /* block_param: f_rest_arg opt_block_args_tail */
+#line 3669 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, 0, 0, (yyvsp[-1].id), 0, (yyvsp[0].nd));
+ }
+#line 9984 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 389: /* block_param: f_rest_arg ',' f_arg opt_block_args_tail */
+#line 3673 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, 0, 0, (yyvsp[-3].id), (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 9992 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 390: /* block_param: block_args_tail */
+#line 3677 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, 0, 0, 0, 0, (yyvsp[0].nd));
+ }
+#line 10000 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 391: /* opt_block_param: none */
+#line 3683 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_add_blk(p);
+ (yyval.nd) = 0;
+ }
+#line 10009 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 392: /* opt_block_param: block_param_def */
+#line 3688 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ p->cmd_start = TRUE;
+ (yyval.nd) = (yyvsp[0].nd);
+ }
+#line 10018 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 393: /* $@27: %empty */
+#line 3694 "mrbgems/mruby-compiler/core/parse.y"
+ {local_add_blk(p);}
+#line 10024 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 394: /* block_param_def: '|' $@27 opt_bv_decl '|' */
+#line 3695 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = 0;
+ }
+#line 10032 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 395: /* block_param_def: "||" */
+#line 3699 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_add_blk(p);
+ (yyval.nd) = 0;
+ }
+#line 10041 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 396: /* block_param_def: '|' block_param opt_bv_decl '|' */
+#line 3704 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-2].nd);
+ }
+#line 10049 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 397: /* opt_bv_decl: opt_nl */
+#line 3710 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = 0;
+ }
+#line 10057 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 398: /* opt_bv_decl: opt_nl ';' bv_decls opt_nl */
+#line 3714 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = 0;
+ }
+#line 10065 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 401: /* bvar: "local variable or method" */
+#line 3724 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_add_f(p, (yyvsp[0].id));
+ new_bv(p, (yyvsp[0].id));
+ }
+#line 10074 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 403: /* f_larglist: '(' f_args opt_bv_decl ')' */
+#line 3732 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-2].nd);
+ }
+#line 10082 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 404: /* f_larglist: f_args */
+#line 3736 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[0].nd);
+ }
+#line 10090 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 405: /* lambda_body: tLAMBEG compstmt '}' */
+#line 3742 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 10098 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 406: /* lambda_body: "'do' for lambda" bodystmt "'end'" */
+#line 3746 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 10106 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 407: /* @28: %empty */
+#line 3752 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_nest(p);
+ nvars_nest(p);
+ (yyval.num) = p->lineno;
+ }
+#line 10116 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 408: /* do_block: "'do' for block" @28 opt_block_param bodystmt "'end'" */
+#line 3760 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_block(p,(yyvsp[-2].nd),(yyvsp[-1].nd));
+ SET_LINENO((yyval.nd), (yyvsp[-3].num));
+ local_unnest(p);
+ nvars_unnest(p);
+ }
+#line 10127 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 409: /* block_call: command do_block */
+#line 3769 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ call_with_block(p, (yyvsp[-1].nd), (yyvsp[0].nd));
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 10136 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 410: /* block_call: block_call call_op2 operation2 opt_paren_args */
+#line 3774 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-3].nd), (yyvsp[-1].id), (yyvsp[0].nd), (yyvsp[-2].num));
+ }
+#line 10144 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 411: /* block_call: block_call call_op2 operation2 opt_paren_args brace_block */
+#line 3778 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-4].nd), (yyvsp[-2].id), (yyvsp[-1].nd), (yyvsp[-3].num));
+ call_with_block(p, (yyval.nd), (yyvsp[0].nd));
+ }
+#line 10153 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 412: /* block_call: block_call call_op2 operation2 command_args do_block */
+#line 3783 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-4].nd), (yyvsp[-2].id), (yyvsp[-1].nd), (yyvsp[-3].num));
+ call_with_block(p, (yyval.nd), (yyvsp[0].nd));
+ }
+#line 10162 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 413: /* method_call: operation paren_args */
+#line 3790 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_fcall(p, (yyvsp[-1].id), (yyvsp[0].nd));
+ }
+#line 10170 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 414: /* method_call: primary_value call_op operation2 opt_paren_args */
+#line 3794 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-3].nd), (yyvsp[-1].id), (yyvsp[0].nd), (yyvsp[-2].num));
+ }
+#line 10178 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 415: /* method_call: primary_value "::" operation2 paren_args */
+#line 3798 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-3].nd), (yyvsp[-1].id), (yyvsp[0].nd), tCOLON2);
+ }
+#line 10186 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 416: /* method_call: primary_value "::" operation3 */
+#line 3802 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-2].nd), (yyvsp[0].id), 0, tCOLON2);
+ }
+#line 10194 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 417: /* method_call: primary_value call_op paren_args */
+#line 3806 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-2].nd), MRB_SYM(call), (yyvsp[0].nd), (yyvsp[-1].num));
+ }
+#line 10202 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 418: /* method_call: primary_value "::" paren_args */
+#line 3810 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-2].nd), MRB_SYM(call), (yyvsp[0].nd), tCOLON2);
+ }
+#line 10210 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 419: /* method_call: "'super'" paren_args */
+#line 3814 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_super(p, (yyvsp[0].nd));
+ }
+#line 10218 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 420: /* method_call: "'super'" */
+#line 3818 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_zsuper(p);
+ }
+#line 10226 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 421: /* method_call: primary_value '[' opt_call_args ']' */
+#line 3822 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_call(p, (yyvsp[-3].nd), intern_op(aref), (yyvsp[-1].nd), '.');
+ }
+#line 10234 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 422: /* @29: %empty */
+#line 3828 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_nest(p);
+ nvars_nest(p);
+ (yyval.num) = p->lineno;
+ }
+#line 10244 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 423: /* brace_block: '{' @29 opt_block_param compstmt '}' */
+#line 3835 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_block(p,(yyvsp[-2].nd),(yyvsp[-1].nd));
+ SET_LINENO((yyval.nd), (yyvsp[-3].num));
+ local_unnest(p);
+ nvars_unnest(p);
+ }
+#line 10255 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 424: /* @30: %empty */
+#line 3842 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_nest(p);
+ nvars_nest(p);
+ (yyval.num) = p->lineno;
+ }
+#line 10265 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 425: /* brace_block: "'do'" @30 opt_block_param bodystmt "'end'" */
+#line 3849 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_block(p,(yyvsp[-2].nd),(yyvsp[-1].nd));
+ SET_LINENO((yyval.nd), (yyvsp[-3].num));
+ local_unnest(p);
+ nvars_unnest(p);
+ }
+#line 10276 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 426: /* case_body: "'when'" args then compstmt cases */
+#line 3860 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = cons(cons((yyvsp[-3].nd), (yyvsp[-1].nd)), (yyvsp[0].nd));
+ }
+#line 10284 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 427: /* cases: opt_else */
+#line 3866 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ if ((yyvsp[0].nd)) {
+ (yyval.nd) = cons(cons(0, (yyvsp[0].nd)), 0);
+ }
+ else {
+ (yyval.nd) = 0;
+ }
+ }
+#line 10297 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 429: /* in_clauses: opt_else */
+#line 3880 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[0].nd) ? list1(new_in(p, NULL, NULL, (yyvsp[0].nd), FALSE)) : 0;
+ }
+#line 10305 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 430: /* $@31: %empty */
+#line 3883 "mrbgems/mruby-compiler/core/parse.y"
+ {p->in_kwarg--;}
+#line 10311 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 431: /* in_clauses: "'in'" p_expr $@31 then compstmt in_clauses */
+#line 3884 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ node *in_clause = new_in(p, (yyvsp[-4].nd), NULL, (yyvsp[-1].nd), FALSE);
+ (yyval.nd) = cons(in_clause, (yyvsp[0].nd));
+ }
+#line 10320 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 432: /* $@32: %empty */
+#line 3888 "mrbgems/mruby-compiler/core/parse.y"
+ {p->in_kwarg--;}
+#line 10326 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 433: /* in_clauses: "'in'" p_expr $@32 "'if' modifier" expr_value then compstmt in_clauses */
+#line 3889 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ node *in_clause = new_in(p, (yyvsp[-6].nd), (yyvsp[-3].nd), (yyvsp[-1].nd), FALSE);
+ (yyval.nd) = cons(in_clause, (yyvsp[0].nd));
+ }
+#line 10335 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 434: /* $@33: %empty */
+#line 3893 "mrbgems/mruby-compiler/core/parse.y"
+ {p->in_kwarg--;}
+#line 10341 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 435: /* in_clauses: "'in'" p_expr $@33 "'unless' modifier" expr_value then compstmt in_clauses */
+#line 3894 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ node *in_clause = new_in(p, (yyvsp[-6].nd), (yyvsp[-3].nd), (yyvsp[-1].nd), TRUE);
+ (yyval.nd) = cons(in_clause, (yyvsp[0].nd));
+ }
+#line 10350 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 437: /* p_expr: p_args_head p_as */
+#line 3905 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_array(p, push((yyvsp[-1].nd), (yyvsp[0].nd)), 0, 0);
+ }
+#line 10358 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 438: /* p_expr: p_args_head p_rest */
+#line 3909 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_array(p, (yyvsp[-1].nd), (yyvsp[0].nd), 0);
+ }
+#line 10366 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 439: /* p_expr: p_args_head p_rest ',' p_args_post */
+#line 3913 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_array(p, (yyvsp[-3].nd), (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 10374 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 440: /* p_expr: p_rest */
+#line 3917 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_array(p, 0, (yyvsp[0].nd), 0);
+ }
+#line 10382 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 441: /* p_expr: p_rest ',' p_args_post */
+#line 3921 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_array(p, 0, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 10390 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 442: /* p_expr: p_hash_elems */
+#line 3925 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* Brace-less hash pattern: in a:, b: x */
+ (yyval.nd) = new_pat_hash(p, (yyvsp[0].nd), 0);
+ }
+#line 10399 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 443: /* p_expr: p_hash_elems ',' p_kwrest */
+#line 3930 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* Brace-less hash pattern with kwrest: in a:, **rest */
+ (yyval.nd) = new_pat_hash(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 10408 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 444: /* p_expr: p_kwrest */
+#line 3935 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* Brace-less kwrest only: in **rest */
+ (yyval.nd) = new_pat_hash(p, 0, (yyvsp[0].nd));
+ }
+#line 10417 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 445: /* p_args_head: p_as ',' */
+#line 3943 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1((yyvsp[-1].nd));
+ }
+#line 10425 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 446: /* p_args_head: p_args_head p_as ',' */
+#line 3947 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-2].nd), (yyvsp[-1].nd));
+ }
+#line 10433 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 447: /* p_args_post: p_as */
+#line 3954 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 10441 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 448: /* p_args_post: p_args_post ',' p_as */
+#line 3958 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 10449 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 450: /* p_as: p_alt "=>" "local variable or method" */
+#line 3965 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_as(p, (yyvsp[-2].nd), (yyvsp[0].id));
+ }
+#line 10457 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 452: /* p_alt: p_alt '|' p_value */
+#line 3972 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_alt(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 10465 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 454: /* p_value: numeric */
+#line 3979 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_value(p, (yyvsp[0].nd));
+ }
+#line 10473 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 455: /* p_value: symbol */
+#line 3983 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_value(p, (yyvsp[0].nd));
+ }
+#line 10481 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 456: /* p_value: tSTRING */
+#line 3987 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_value(p, new_str(p, list1((yyvsp[0].nd))));
+ }
+#line 10489 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 457: /* p_value: "'nil'" */
+#line 3991 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_value(p, new_nil(p));
+ }
+#line 10497 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 458: /* p_value: "'true'" */
+#line 3995 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_value(p, new_true(p));
+ }
+#line 10505 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 459: /* p_value: "'false'" */
+#line 3999 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_value(p, new_false(p));
+ }
+#line 10513 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 460: /* p_value: p_const */
+#line 4003 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_value(p, (yyvsp[0].nd));
+ }
+#line 10521 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 463: /* p_value: '^' "local variable or method" */
+#line 4009 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_pin(p, (yyvsp[0].id));
+ }
+#line 10529 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 464: /* p_array: "[" p_array_body ']' */
+#line 4016 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 10537 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 465: /* p_array: "[" ']' */
+#line 4020 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_array(p, 0, 0, 0);
+ }
+#line 10545 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 466: /* p_array_body: p_array_elems */
+#line 4027 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* Just pre elements, no rest */
+ (yyval.nd) = new_pat_array(p, (yyvsp[0].nd), 0, 0);
+ }
+#line 10554 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 467: /* p_array_body: p_array_elems ',' p_rest */
+#line 4032 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* Pre elements + rest, no post */
+ (yyval.nd) = new_pat_array(p, (yyvsp[-2].nd), (yyvsp[0].nd), 0);
+ }
+#line 10563 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 468: /* p_array_body: p_array_elems ',' p_rest ',' p_array_elems */
+#line 4037 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* Pre + rest + post */
+ (yyval.nd) = new_pat_array(p, (yyvsp[-4].nd), (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 10572 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 469: /* p_array_body: p_rest */
+#line 4042 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* Just rest, no pre or post */
+ (yyval.nd) = new_pat_array(p, 0, (yyvsp[0].nd), 0);
+ }
+#line 10581 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 470: /* p_array_body: p_rest ',' p_array_elems */
+#line 4047 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* Rest + post, no pre */
+ (yyval.nd) = new_pat_array(p, 0, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 10590 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 471: /* p_array_body: p_rest ',' p_array_elems ',' p_rest */
+#line 4052 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* Find pattern: [*pre, elems, *post] */
+ (yyval.nd) = new_pat_find(p, (yyvsp[-4].nd), (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 10599 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 472: /* p_array_elems: p_as */
+#line 4060 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 10607 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 473: /* p_array_elems: p_array_elems ',' p_as */
+#line 4064 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 10615 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 474: /* p_rest: "*" "local variable or method" */
+#line 4071 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_var(p, (yyvsp[0].id));
+ }
+#line 10623 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 475: /* p_rest: "*" */
+#line 4075 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* Anonymous rest pattern */
+ (yyval.nd) = (node*)-1;
+ }
+#line 10632 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 476: /* p_const: "constant" */
+#line 4083 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_const(p, (yyvsp[0].id));
+ }
+#line 10640 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 477: /* p_const: p_const "::" "constant" */
+#line 4087 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_colon2(p, (yyvsp[-2].nd), (yyvsp[0].id));
+ }
+#line 10648 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 478: /* p_const: tCOLON3 "constant" */
+#line 4091 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_colon3(p, (yyvsp[0].id));
+ }
+#line 10656 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 479: /* p_hash: tLBRACE p_hash_body '}' */
+#line 4098 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 10664 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 480: /* p_hash: tLBRACE '}' */
+#line 4102 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_hash(p, 0, 0);
+ }
+#line 10672 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 481: /* p_hash_body: p_hash_elems */
+#line 4109 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_hash(p, (yyvsp[0].nd), 0);
+ }
+#line 10680 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 482: /* p_hash_body: p_hash_elems ',' p_kwrest */
+#line 4113 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_hash(p, (yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 10688 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 483: /* p_hash_body: p_kwrest */
+#line 4117 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_hash(p, 0, (yyvsp[0].nd));
+ }
+#line 10696 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 484: /* p_hash_elems: p_hash_elem */
+#line 4124 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 10704 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 485: /* p_hash_elems: p_hash_elems ',' p_hash_elem */
+#line 4128 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 10712 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 486: /* p_hash_elem: "local variable or method" "label" p_as */
+#line 4137 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* {key: pattern} */
+ (yyval.nd) = cons(new_sym(p, (yyvsp[-2].id)), (yyvsp[0].nd));
+ }
+#line 10721 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 487: /* p_hash_elem: "local variable or method" "label" */
+#line 4142 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* {key:} shorthand - binds to variable with same name */
+ (yyval.nd) = cons(new_sym(p, (yyvsp[-1].id)), new_pat_var(p, (yyvsp[-1].id)));
+ }
+#line 10730 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 488: /* p_kwrest: "**" "local variable or method" */
+#line 4150 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_var(p, (yyvsp[0].id));
+ }
+#line 10738 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 489: /* p_kwrest: "**" "'nil'" */
+#line 4154 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* **nil - exact match, no extra keys allowed */
+ (yyval.nd) = (node*)-1;
+ }
+#line 10747 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 490: /* p_kwrest: "**" */
+#line 4159 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* ** - anonymous rest, discards extra keys */
+ (yyval.nd) = (node*)-2;
+ }
+#line 10756 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 491: /* p_var: "local variable or method" */
+#line 4166 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_pat_var(p, (yyvsp[0].id));
+ }
+#line 10764 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 492: /* opt_rescue: "'rescue'" exc_list exc_var then compstmt opt_rescue */
+#line 4174 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1(list3((yyvsp[-4].nd), (yyvsp[-3].nd), (yyvsp[-1].nd)));
+ if ((yyvsp[0].nd)) (yyval.nd) = append((yyval.nd), (yyvsp[0].nd));
+ }
+#line 10773 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 494: /* exc_list: arg */
+#line 4182 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 10781 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 497: /* exc_var: "=>" lhs */
+#line 4190 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[0].nd);
+ }
+#line 10789 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 499: /* opt_ensure: "'ensure'" compstmt */
+#line 4197 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[0].nd);
+ }
+#line 10797 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 506: /* string: string string_fragment */
+#line 4211 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = append((yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 10805 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 507: /* string_fragment: "character literal" */
+#line 4217 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* tCHAR is (len . str), wrap as cons list */
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 10814 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 508: /* string_fragment: tSTRING */
+#line 4222 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* tSTRING is (len . str), wrap as cons list */
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 10823 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 509: /* string_fragment: "string literal" tSTRING */
+#line 4227 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* $2 is (len . str), wrap as cons list */
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 10832 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 510: /* string_fragment: "string literal" string_rep tSTRING */
+#line 4232 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 10840 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 512: /* string_rep: string_rep string_interp */
+#line 4239 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = append((yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 10848 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 513: /* string_interp: tSTRING_MID */
+#line 4245 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ /* $1 is already in (len . str) format */
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 10857 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 514: /* @34: %empty */
+#line 4250 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push_strterm(p);
+ }
+#line 10865 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 515: /* string_interp: tSTRING_PART @34 compstmt '}' */
+#line 4255 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ pop_strterm(p,(yyvsp[-2].nd));
+ /* $1 is already in (len . str) format, create (-1 . node) for expression */
+ node *expr_elem = cons(int_to_node(-1), (yyvsp[-1].nd));
+ (yyval.nd) = list2((yyvsp[-3].nd), expr_elem);
+ }
+#line 10876 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 516: /* string_interp: tLITERAL_DELIM */
+#line 4262 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1(new_literal_delim(p));
+ }
+#line 10884 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 517: /* string_interp: tHD_LITERAL_DELIM heredoc_bodies */
+#line 4266 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1(new_literal_delim(p));
+ }
+#line 10892 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 518: /* xstring: tXSTRING_BEG tXSTRING */
+#line 4272 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = cons((yyvsp[0].nd), (node*)NULL);
+ }
+#line 10900 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 519: /* xstring: tXSTRING_BEG string_rep tXSTRING */
+#line 4276 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 10908 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 520: /* regexp: tREGEXP_BEG tREGEXP */
+#line 4282 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ node *data = (yyvsp[0].nd); /* ((len . pattern) . (flags . encoding)) */
+ const char *flags = (const char*)data->cdr->car;
+ const char *encoding = (const char*)data->cdr->cdr;
+ /* Use data->car directly as pattern_list: (len . pattern) */
+ node *pattern_list = cons(data->car, (node*)NULL);
+ (yyval.nd) = new_regx(p, pattern_list, flags, encoding);
+ }
+#line 10921 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 521: /* regexp: tREGEXP_BEG string_rep tREGEXP */
+#line 4291 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ node *data = (yyvsp[0].nd); /* ((len . pattern) . (flags . encoding)) */
+ const char *flags = (const char*)data->cdr->car;
+ const char *encoding = (const char*)data->cdr->cdr;
+ /* Append the pattern from $3->car to the string list $2 */
+ node *complete_list = push((yyvsp[-1].nd), data->car);
+ (yyval.nd) = new_regx(p, complete_list, flags, encoding);
+ }
+#line 10934 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 525: /* heredoc_body: tHEREDOC_END */
+#line 4309 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ parser_heredoc_info *info = parsing_heredoc_info(p);
+ info->doc = push(info->doc, new_str_empty(p));
+ heredoc_end(p);
+ }
+#line 10944 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 526: /* heredoc_body: heredoc_string_rep tHEREDOC_END */
+#line 4315 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ heredoc_end(p);
+ }
+#line 10952 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 529: /* heredoc_string_interp: tHD_STRING_MID */
+#line 4325 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ parser_heredoc_info *info = parsing_heredoc_info(p);
+ info->doc = push(info->doc, (yyvsp[0].nd));
+ heredoc_treat_nextline(p);
+ }
+#line 10962 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 530: /* @35: %empty */
+#line 4331 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push_strterm(p);
+ }
+#line 10970 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 531: /* heredoc_string_interp: tHD_STRING_PART @35 compstmt '}' */
+#line 4336 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ pop_strterm(p, (yyvsp[-2].nd));
+ parser_heredoc_info *info = parsing_heredoc_info(p);
+ /* $1 is already in (len . str) format, create (-1 . node) for expression */
+ node *expr_elem = cons(int_to_node(-1), (yyvsp[-1].nd));
+ info->doc = push(push(info->doc, (yyvsp[-3].nd)), expr_elem);
+ }
+#line 10982 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 532: /* words: tWORDS_BEG tSTRING */
+#line 4346 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_words(p, list1((yyvsp[0].nd)));
+ }
+#line 10990 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 533: /* words: tWORDS_BEG string_rep tSTRING */
+#line 4350 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ node *n = (yyvsp[-1].nd);
+ n = push(n, (yyvsp[0].nd));
+ (yyval.nd) = new_words(p, n);
+ }
+#line 11000 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 534: /* symbol: basic_symbol */
+#line 4358 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_sym(p, (yyvsp[0].id));
+ }
+#line 11008 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 535: /* symbol: "symbol" "string literal" string_rep tSTRING */
+#line 4362 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ node *n = (yyvsp[-1].nd);
+ p->lstate = EXPR_ENDARG;
+ if (node_to_int((yyvsp[0].nd)->car) > 0) {
+ n = push(n, (yyvsp[0].nd));
+ }
+ else {
+ cons_free((yyvsp[0].nd));
+ }
+ (yyval.nd) = new_dsym(p, n);
+ }
+#line 11024 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 536: /* symbol: "symbol" "numbered parameter" */
+#line 4374 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ mrb_sym sym = intern_numparam((yyvsp[0].num));
+ (yyval.nd) = new_sym(p, sym);
+ }
+#line 11033 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 537: /* basic_symbol: "symbol" sym */
+#line 4381 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ p->lstate = EXPR_END;
+ (yyval.id) = (yyvsp[0].id);
+ }
+#line 11042 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 542: /* sym: tSTRING */
+#line 4392 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.id) = new_strsym(p, (yyvsp[0].nd));
+ }
+#line 11050 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 543: /* sym: "string literal" tSTRING */
+#line 4396 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.id) = new_strsym(p, (yyvsp[0].nd));
+ }
+#line 11058 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 544: /* symbols: tSYMBOLS_BEG tSTRING */
+#line 4402 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_symbols(p, list1((yyvsp[0].nd)));
+ }
+#line 11066 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 545: /* symbols: tSYMBOLS_BEG string_rep tSTRING */
+#line 4406 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ node *n = (yyvsp[-1].nd);
+ n = push(n, (yyvsp[0].nd));
+ (yyval.nd) = new_symbols(p, n);
+ }
+#line 11076 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 548: /* numeric: tUMINUS_NUM "integer literal" */
+#line 4416 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_negate(p, (yyvsp[0].nd));
+ }
+#line 11084 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 549: /* numeric: tUMINUS_NUM "float literal" */
+#line 4420 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_negate(p, (yyvsp[0].nd));
+ }
+#line 11092 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 550: /* variable: "local variable or method" */
+#line 4426 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_lvar(p, (yyvsp[0].id));
+ }
+#line 11100 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 551: /* variable: "instance variable" */
+#line 4430 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_ivar(p, (yyvsp[0].id));
+ }
+#line 11108 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 552: /* variable: "global variable" */
+#line 4434 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_gvar(p, (yyvsp[0].id));
+ }
+#line 11116 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 553: /* variable: "class variable" */
+#line 4438 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_cvar(p, (yyvsp[0].id));
+ }
+#line 11124 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 554: /* variable: "constant" */
+#line 4442 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_const(p, (yyvsp[0].id));
+ }
+#line 11132 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 555: /* var_lhs: variable */
+#line 4448 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ assignable(p, (yyvsp[0].nd));
+ }
+#line 11140 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 556: /* var_lhs: "numbered parameter" */
+#line 4452 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ yyerror(&(yylsp[0]), p, "can't assign to numbered parameter");
+ }
+#line 11148 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 557: /* var_ref: variable */
+#line 4458 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = var_reference(p, (yyvsp[0].nd));
+ }
+#line 11156 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 558: /* var_ref: "numbered parameter" */
+#line 4462 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_nvar(p, (yyvsp[0].num));
+ }
+#line 11164 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 559: /* var_ref: "'nil'" */
+#line 4466 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_nil(p);
+ }
+#line 11172 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 560: /* var_ref: "'self'" */
+#line 4470 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_self(p);
+ }
+#line 11180 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 561: /* var_ref: "'true'" */
+#line 4474 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_true(p);
+ }
+#line 11188 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 562: /* var_ref: "'false'" */
+#line 4478 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_false(p);
+ }
+#line 11196 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 563: /* var_ref: "'__FILE__'" */
+#line 4482 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ const char *fn = mrb_sym_name_len(p->mrb, p->filename_sym, NULL);
+ if (!fn) {
+ fn = "(null)";
+ }
+ (yyval.nd) = new_str(p, cons(cons(int_to_node(strlen(fn)), (node*)fn), (node*)NULL));
+ }
+#line 11208 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 564: /* var_ref: "'__LINE__'" */
+#line 4490 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ char buf[16];
+
+ dump_int(p->lineno, buf);
+ (yyval.nd) = new_int(p, buf, 10, 0);
+ }
+#line 11219 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 565: /* var_ref: "'__ENCODING__'" */
+#line 4497 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_fcall(p, MRB_SYM(__ENCODING__), 0);
+ }
+#line 11227 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 568: /* superclass: %empty */
+#line 4507 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = 0;
+ }
+#line 11235 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 569: /* $@36: %empty */
+#line 4511 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ p->lstate = EXPR_BEG;
+ p->cmd_start = TRUE;
+ }
+#line 11244 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 570: /* superclass: '<' $@36 expr_value term */
+#line 4516 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 11252 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 573: /* f_arglist_paren: '(' f_args rparen */
+#line 4532 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ p->lstate = EXPR_BEG;
+ p->cmd_start = TRUE;
+ }
+#line 11262 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 574: /* f_arglist_paren: '(' f_arg ',' tBDOT3 rparen */
+#line 4538 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_dots(p, (yyvsp[-3].nd));
+ }
+#line 11270 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 575: /* f_arglist_paren: '(' tBDOT3 rparen */
+#line 4542 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_dots(p, 0);
+ }
+#line 11278 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 577: /* f_arglist: f_args term */
+#line 4549 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 11286 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 578: /* f_arglist: f_arg ',' tBDOT3 term */
+#line 4553 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_dots(p, (yyvsp[-3].nd));
+ }
+#line 11294 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 579: /* f_arglist: "..." term */
+#line 4557 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_dots(p, 0);
+ }
+#line 11302 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 580: /* f_label: "local variable or method" "label" */
+#line 4563 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.id) = (yyvsp[-1].id);
+ local_nest(p);
+ p->lstate = EXPR_MID; /* make newlines significant after label */
+ }
+#line 11312 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 581: /* f_label: "numbered parameter" "label" */
+#line 4569 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.id) = intern_numparam((yyvsp[-1].num));
+ local_nest(p);
+ p->lstate = EXPR_MID; /* make newlines significant after label */
+ }
+#line 11322 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 582: /* f_kw: f_label arg */
+#line 4577 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[0].nd));
+ (yyval.nd) = new_kw_arg(p, (yyvsp[-1].id), cons((yyvsp[0].nd), locals_node(p)));
+ local_unnest(p);
+ }
+#line 11332 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 583: /* f_kw: f_label */
+#line 4583 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_kw_arg(p, (yyvsp[0].id), 0);
+ local_unnest(p);
+ }
+#line 11341 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 584: /* f_block_kw: f_label primary_value */
+#line 4590 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[0].nd));
+ (yyval.nd) = new_kw_arg(p, (yyvsp[-1].id), cons((yyvsp[0].nd), locals_node(p)));
+ local_unnest(p);
+ }
+#line 11351 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 585: /* f_block_kw: f_label */
+#line 4596 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_kw_arg(p, (yyvsp[0].id), 0);
+ local_unnest(p);
+ }
+#line 11360 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 586: /* f_block_kwarg: f_block_kw */
+#line 4603 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 11368 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 587: /* f_block_kwarg: f_block_kwarg ',' f_block_kw */
+#line 4607 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 11376 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 588: /* f_kwarg: f_kw */
+#line 4613 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 11384 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 589: /* f_kwarg: f_kwarg ',' f_kw */
+#line 4617 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 11392 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 592: /* f_kwrest: kwrest_mark "local variable or method" */
+#line 4627 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.id) = (yyvsp[0].id);
+ }
+#line 11400 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 593: /* f_kwrest: kwrest_mark */
+#line 4631 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.id) = intern_op(pow);
+ }
+#line 11408 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 594: /* args_tail: f_kwarg ',' f_kwrest opt_f_block_arg */
+#line 4637 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_tail(p, (yyvsp[-3].nd), (yyvsp[-1].id), (yyvsp[0].id));
+ }
+#line 11416 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 595: /* args_tail: f_kwarg opt_f_block_arg */
+#line 4641 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_tail(p, (yyvsp[-1].nd), 0, (yyvsp[0].id));
+ }
+#line 11424 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 596: /* args_tail: f_kwrest opt_f_block_arg */
+#line 4645 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_tail(p, 0, (yyvsp[-1].id), (yyvsp[0].id));
+ }
+#line 11432 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 597: /* args_tail: f_block_arg */
+#line 4649 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_tail(p, 0, 0, (yyvsp[0].id));
+ }
+#line 11440 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 598: /* opt_args_tail: ',' args_tail */
+#line 4655 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[0].nd);
+ }
+#line 11448 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 599: /* opt_args_tail: ',' */
+#line 4659 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_tail(p, 0, 0, 0);
+ }
+#line 11456 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 600: /* opt_args_tail: %empty */
+#line 4663 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args_tail(p, 0, 0, 0);
+ }
+#line 11464 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 601: /* f_args: f_arg ',' f_optarg ',' f_rest_arg opt_args_tail */
+#line 4669 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-5].nd), (yyvsp[-3].nd), (yyvsp[-1].id), 0, (yyvsp[0].nd));
+ }
+#line 11472 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 602: /* f_args: f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_args_tail */
+#line 4673 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-7].nd), (yyvsp[-5].nd), (yyvsp[-3].id), (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 11480 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 603: /* f_args: f_arg ',' f_optarg opt_args_tail */
+#line 4677 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-3].nd), (yyvsp[-1].nd), 0, 0, (yyvsp[0].nd));
+ }
+#line 11488 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 604: /* f_args: f_arg ',' f_optarg ',' f_arg opt_args_tail */
+#line 4681 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-5].nd), (yyvsp[-3].nd), 0, (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 11496 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 605: /* f_args: f_arg ',' f_rest_arg opt_args_tail */
+#line 4685 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-3].nd), 0, (yyvsp[-1].id), 0, (yyvsp[0].nd));
+ }
+#line 11504 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 606: /* f_args: f_arg ',' f_rest_arg ',' f_arg opt_args_tail */
+#line 4689 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-5].nd), 0, (yyvsp[-3].id), (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 11512 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 607: /* f_args: f_arg opt_args_tail */
+#line 4693 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, (yyvsp[-1].nd), 0, 0, 0, (yyvsp[0].nd));
+ }
+#line 11520 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 608: /* f_args: f_optarg ',' f_rest_arg opt_args_tail */
+#line 4697 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, 0, (yyvsp[-3].nd), (yyvsp[-1].id), 0, (yyvsp[0].nd));
+ }
+#line 11528 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 609: /* f_args: f_optarg ',' f_rest_arg ',' f_arg opt_args_tail */
+#line 4701 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, 0, (yyvsp[-5].nd), (yyvsp[-3].id), (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 11536 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 610: /* f_args: f_optarg opt_args_tail */
+#line 4705 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, 0, (yyvsp[-1].nd), 0, 0, (yyvsp[0].nd));
+ }
+#line 11544 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 611: /* f_args: f_optarg ',' f_arg opt_args_tail */
+#line 4709 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, 0, (yyvsp[-3].nd), 0, (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 11552 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 612: /* f_args: f_rest_arg opt_args_tail */
+#line 4713 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, 0, 0, (yyvsp[-1].id), 0, (yyvsp[0].nd));
+ }
+#line 11560 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 613: /* f_args: f_rest_arg ',' f_arg opt_args_tail */
+#line 4717 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, 0, 0, (yyvsp[-3].id), (yyvsp[-1].nd), (yyvsp[0].nd));
+ }
+#line 11568 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 614: /* f_args: args_tail */
+#line 4721 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_args(p, 0, 0, 0, 0, (yyvsp[0].nd));
+ }
+#line 11576 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 615: /* f_args: %empty */
+#line 4725 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_add_f(p, 0);
+ (yyval.nd) = new_args(p, 0, 0, 0, 0, 0);
+ }
+#line 11585 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 616: /* f_bad_arg: "constant" */
+#line 4732 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ yyerror(&(yylsp[0]), p, "formal argument cannot be a constant");
+ (yyval.nd) = 0;
+ }
+#line 11594 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 617: /* f_bad_arg: "instance variable" */
+#line 4737 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ yyerror(&(yylsp[0]), p, "formal argument cannot be an instance variable");
+ (yyval.nd) = 0;
+ }
+#line 11603 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 618: /* f_bad_arg: "global variable" */
+#line 4742 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ yyerror(&(yylsp[0]), p, "formal argument cannot be a global variable");
+ (yyval.nd) = 0;
+ }
+#line 11612 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 619: /* f_bad_arg: "class variable" */
+#line 4747 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ yyerror(&(yylsp[0]), p, "formal argument cannot be a class variable");
+ (yyval.nd) = 0;
+ }
+#line 11621 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 620: /* f_bad_arg: "numbered parameter" */
+#line 4752 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ yyerror(&(yylsp[0]), p, "formal argument cannot be a numbered parameter");
+ (yyval.nd) = 0;
+ }
+#line 11630 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 621: /* f_norm_arg: f_bad_arg */
+#line 4759 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.id) = 0;
+ }
+#line 11638 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 622: /* f_norm_arg: "local variable or method" */
+#line 4763 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_add_f(p, (yyvsp[0].id));
+ (yyval.id) = (yyvsp[0].id);
+ }
+#line 11647 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 623: /* f_arg_item: f_norm_arg */
+#line 4770 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_lvar(p, (yyvsp[0].id));
+ }
+#line 11655 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 624: /* @37: %empty */
+#line 4774 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = local_switch(p);
+ }
+#line 11663 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 625: /* f_arg_item: tLPAREN @37 f_margs rparen */
+#line 4778 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = new_marg(p, (yyvsp[-1].nd));
+ local_resume(p, (yyvsp[-2].nd));
+ local_add_f(p, 0);
+ }
+#line 11673 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 626: /* f_arg: f_arg_item */
+#line 4786 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 11681 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 627: /* f_arg: f_arg ',' f_arg_item */
+#line 4790 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 11689 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 628: /* f_opt_asgn: "local variable or method" '=' */
+#line 4796 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_add_f(p, (yyvsp[-1].id));
+ local_nest(p);
+ (yyval.id) = (yyvsp[-1].id);
+ }
+#line 11699 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 629: /* f_opt: f_opt_asgn arg */
+#line 4804 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[0].nd));
+ (yyval.nd) = cons(sym_to_node((yyvsp[-1].id)), cons((yyvsp[0].nd), locals_node(p)));
+ local_unnest(p);
+ }
+#line 11709 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 630: /* f_block_opt: f_opt_asgn primary_value */
+#line 4812 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[0].nd));
+ (yyval.nd) = cons(sym_to_node((yyvsp[-1].id)), cons((yyvsp[0].nd), locals_node(p)));
+ local_unnest(p);
+ }
+#line 11719 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 631: /* f_block_optarg: f_block_opt */
+#line 4820 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 11727 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 632: /* f_block_optarg: f_block_optarg ',' f_block_opt */
+#line 4824 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 11735 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 633: /* f_optarg: f_opt */
+#line 4830 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 11743 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 634: /* f_optarg: f_optarg ',' f_opt */
+#line 4834 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 11751 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 637: /* f_rest_arg: restarg_mark "local variable or method" */
+#line 4844 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ local_add_f(p, (yyvsp[0].id));
+ (yyval.id) = (yyvsp[0].id);
+ }
+#line 11760 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 638: /* f_rest_arg: restarg_mark */
+#line 4849 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.id) = intern_op(mul);
+ local_add_f(p, (yyval.id));
+ }
+#line 11769 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 641: /* f_block_arg: blkarg_mark "local variable or method" */
+#line 4860 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.id) = (yyvsp[0].id);
+ }
+#line 11777 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 642: /* f_block_arg: blkarg_mark "'nil'" */
+#line 4864 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.id) = MRB_SYM(nil);
+ }
+#line 11785 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 643: /* f_block_arg: blkarg_mark */
+#line 4868 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.id) = intern_op(and);
+ }
+#line 11793 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 644: /* opt_f_block_arg: ',' f_block_arg */
+#line 4874 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.id) = (yyvsp[0].id);
+ }
+#line 11801 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 645: /* opt_f_block_arg: ',' */
+#line 4878 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.id) = 0;
+ }
+#line 11809 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 646: /* opt_f_block_arg: none */
+#line 4882 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.id) = 0;
+ }
+#line 11817 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 647: /* singleton: var_ref */
+#line 4888 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ prohibit_literals(p, (yyvsp[0].nd));
+ (yyval.nd) = (yyvsp[0].nd);
+ if (!(yyval.nd)) (yyval.nd) = new_nil(p);
+ }
+#line 11827 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 648: /* $@38: %empty */
+#line 4893 "mrbgems/mruby-compiler/core/parse.y"
+ {p->lstate = EXPR_BEG;}
+#line 11833 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 649: /* singleton: '(' $@38 expr rparen */
+#line 4894 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ prohibit_literals(p, (yyvsp[-1].nd));
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 11842 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 651: /* assoc_list: assocs trailer */
+#line 4902 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = (yyvsp[-1].nd);
+ }
+#line 11850 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 652: /* assocs: assoc */
+#line 4908 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = list1((yyvsp[0].nd));
+ }
+#line 11858 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 653: /* assocs: assocs comma assoc */
+#line 4912 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = push((yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 11866 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 654: /* assoc: arg "=>" arg */
+#line 4918 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[-2].nd));
+ void_expr_error(p, (yyvsp[0].nd));
+ (yyval.nd) = cons((yyvsp[-2].nd), (yyvsp[0].nd));
+ }
+#line 11876 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 655: /* assoc: "local variable or method" "label" arg */
+#line 4924 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[0].nd));
+ (yyval.nd) = cons(new_sym(p, (yyvsp[-2].id)), (yyvsp[0].nd));
+ }
+#line 11885 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 656: /* assoc: "local variable or method" "label" */
+#line 4929 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = cons(new_sym(p, (yyvsp[-1].id)), label_reference(p, (yyvsp[-1].id)));
+ }
+#line 11893 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 657: /* assoc: "numbered parameter" "label" */
+#line 4933 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ mrb_sym sym = intern_numparam((yyvsp[-1].num));
+ (yyval.nd) = cons(new_sym(p, sym), label_reference(p, sym));
+ }
+#line 11902 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 658: /* assoc: "numbered parameter" "label" arg */
+#line 4938 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[0].nd));
+ (yyval.nd) = cons(new_sym(p, intern_numparam((yyvsp[-2].num))), (yyvsp[0].nd));
+ }
+#line 11911 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 659: /* assoc: string_fragment "label" arg */
+#line 4943 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[0].nd));
+ if ((yyvsp[-2].nd)->cdr) {
+ /* Multiple fragments - create dynamic symbol */
+ (yyval.nd) = cons(new_dsym(p, (yyvsp[-2].nd)), (yyvsp[0].nd));
+ }
+ else if (node_to_int((yyvsp[-2].nd)->car->car) < 0) {
+ /* Single fragment but it's an expression (-1 . node) - create dynamic symbol */
+ (yyval.nd) = cons(new_dsym(p, (yyvsp[-2].nd)), (yyvsp[0].nd));
+ }
+ else {
+ /* Single string fragment - create simple symbol */
+ (yyval.nd) = cons(new_sym(p, new_strsym(p, (yyvsp[-2].nd)->car)), (yyvsp[0].nd));
+ }
+ }
+#line 11931 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 660: /* assoc: "**" arg */
+#line 4959 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ void_expr_error(p, (yyvsp[0].nd));
+ (yyval.nd) = cons(new_kw_rest_args(p, 0), (yyvsp[0].nd));
+ }
+#line 11940 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 661: /* assoc: "**" */
+#line 4964 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = cons(new_kw_rest_args(p, 0), new_lvar(p, intern_op(pow)));
+ }
+#line 11948 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 674: /* call_op: '.' */
+#line 4990 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.num) = '.';
+ }
+#line 11956 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 675: /* call_op: "&." */
+#line 4994 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.num) = 0;
+ }
+#line 11964 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 677: /* call_op2: "::" */
+#line 5001 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.num) = tCOLON2;
+ }
+#line 11972 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 686: /* term: ';' */
+#line 5022 "mrbgems/mruby-compiler/core/parse.y"
+ {yyerrok;}
+#line 11978 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 688: /* nl: '\n' */
+#line 5027 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ p->lineno += (yyvsp[0].num);
+ p->column = 0;
+ }
+#line 11987 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+ case 692: /* none: %empty */
+#line 5039 "mrbgems/mruby-compiler/core/parse.y"
+ {
+ (yyval.nd) = 0;
+ }
+#line 11995 "mrbgems/mruby-compiler/core/y.tab.c"
+ break;
+
+
+#line 11999 "mrbgems/mruby-compiler/core/y.tab.c"
+
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc, p);
+
+ YYPOPSTACK (yylen);
+
+ yylen = 0;
+
+ *++yyvsp = yyval;
+ *++yylsp = yyloc;
+
+ /* Now 'shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+ {
+ const int yylhs = yyr1[yyn] - YYNTOKENS;
+ const int yyi = yypgoto[yylhs] + *yyssp;
+ yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp
+ ? yytable[yyi]
+ : yydefgoto[yylhs]);
+ }
+
+ goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error. |
+`--------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+ {
+ yypcontext_t yyctx
+ = {yyssp, yytoken, &yylloc};
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx, p);
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == -1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = YY_CAST (char *,
+ YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc)));
+ if (yymsg)
+ {
+ yysyntax_error_status
+ = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx, p);
+ yymsgp = yymsg;
+ }
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = YYENOMEM;
+ }
+ }
+ yyerror (&yylloc, p, yymsgp);
+ if (yysyntax_error_status == YYENOMEM)
+ YYNOMEM;
+ }
+ }
+
+ yyerror_range[1] = yylloc;
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, &yylloc, p);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+ /* Pacify compilers when the user code never invokes YYERROR and the
+ label yyerrorlab therefore never appears in user code. */
+ if (0)
+ YYERROR;
+ ++yynerrs;
+
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp, p);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ /* Pop stack until we find a state that shifts the error token. */
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYSYMBOL_YYerror;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ yyerror_range[1] = *yylsp;
+ yydestruct ("Error: popping",
+ YY_ACCESSING_SYMBOL (yystate), yyvsp, yylsp, p);
+ YYPOPSTACK (1);
+
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp, p);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ yyerror_range[2] = yylloc;
+ ++yylsp;
+ YYLLOC_DEFAULT (*yylsp, yyerror_range, 2);
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp, p);
+
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturnlab;
+
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturnlab;
+
+
+/*-----------------------------------------------------------.
+| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. |
+`-----------------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (&yylloc, p, YY_("memory exhausted"));
+ yyresult = 2;
+ goto yyreturnlab;
+
+
+/*----------------------------------------------------------.
+| yyreturnlab -- parsing is finished, clean up and return. |
+`----------------------------------------------------------*/
+yyreturnlab:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, &yylloc, p);
+ }
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp, p);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yylsp, p);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ return yyresult;
+}
+
+#line 5043 "mrbgems/mruby-compiler/core/parse.y"
+
+#define pylval (*((YYSTYPE*)(p->ylval)))
+
+static void
+yyerror(void *lp, parser_state *p, const char *s)
+{
+ char* c;
+ size_t n;
+
+ if (! p->capture_errors) {
+#ifndef MRB_NO_STDIO
+ if (p->filename_sym) {
+ const char *filename = mrb_sym_name_len(p->mrb, p->filename_sym, NULL);
+ fprintf(stderr, "%s:%d:%d: %s\n", filename, p->lineno, p->column, s);
+ }
+ else {
+ fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s);
+ }
+#endif
+ }
+ else if (p->nerr < sizeof(p->error_buffer) / sizeof(p->error_buffer[0])) {
+ n = strlen(s);
+ c = (char*)parser_palloc(p, n + 1);
+ memcpy(c, s, n + 1);
+ p->error_buffer[p->nerr].message = c;
+ p->error_buffer[p->nerr].lineno = p->lineno;
+ p->error_buffer[p->nerr].column = p->column;
+ }
+ p->nerr++;
+}
+
+static void
+yyerror_c(parser_state *p, const char *msg, char c)
+{
+ char buf[256];
+
+ strncpy(buf, msg, sizeof(buf) - 2);
+ buf[sizeof(buf) - 2] = '\0';
+ strncat(buf, &c, 1);
+ yyerror(NULL, p, buf);
+}
+
+static void
+yywarning(parser_state *p, const char *s)
+{
+ char* c;
+ size_t n;
+
+ if (! p->capture_errors) {
+#ifndef MRB_NO_STDIO
+ if (p->filename_sym) {
+ const char *filename = mrb_sym_name_len(p->mrb, p->filename_sym, NULL);
+ fprintf(stderr, "%s:%d:%d: warning: %s\n", filename, p->lineno, p->column, s);
+ }
+ else {
+ fprintf(stderr, "line %d:%d: warning: %s\n", p->lineno, p->column, s);
+ }
+#endif
+ }
+ else if (p->nwarn < sizeof(p->warn_buffer) / sizeof(p->warn_buffer[0])) {
+ n = strlen(s);
+ c = (char*)parser_palloc(p, n + 1);
+ memcpy(c, s, n + 1);
+ p->warn_buffer[p->nwarn].message = c;
+ p->warn_buffer[p->nwarn].lineno = p->lineno;
+ p->warn_buffer[p->nwarn].column = p->column;
+ }
+ p->nwarn++;
+}
+
+static void
+yywarning_s(parser_state *p, const char *msg, const char *s)
+{
+ char buf[256];
+
+ strncpy(buf, msg, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ strncat(buf, ": ", sizeof(buf) - strlen(buf) - 1);
+ strncat(buf, s, sizeof(buf) - strlen(buf) - 1);
+ yywarning(p, buf);
+}
+
+static void
+backref_error(parser_state *p, node *n)
+{
+ int c;
+
+ c = node_to_int(n->car);
+
+ if (c == NODE_NTH_REF) {
+ yyerror_c(p, "can't set variable $", (char)node_to_int(n->cdr)+'0');
+ }
+ else if (c == NODE_BACK_REF) {
+ yyerror_c(p, "can't set variable $", (char)node_to_int(n->cdr));
+ }
+ else {
+ yyerror(NULL, p, "Internal error in backref_error()");
+ }
+}
+
+static void
+void_expr_error(parser_state *p, node *n)
+{
+ if (n == NULL) return;
+
+ /* Check if this is a variable-sized node first */
+ struct mrb_ast_var_header *header = (struct mrb_ast_var_header*)n;
+ if (header) {
+ /* Handle variable-sized nodes */
+ switch ((enum node_type)header->node_type) {
+ case NODE_BREAK:
+ case NODE_RETURN:
+ case NODE_NEXT:
+ case NODE_REDO:
+ case NODE_RETRY:
+ yyerror(NULL, p, "void value expression");
+ return;
+ case NODE_AND:
+ case NODE_OR:
+ {
+ struct mrb_ast_and_node *and_n = (struct mrb_ast_and_node*)n;
+ void_expr_error(p, (node*)and_n->left);
+ void_expr_error(p, (node*)and_n->right);
+ }
+ return;
+ case NODE_STMTS:
+ {
+ struct mrb_ast_stmts_node *stmts = (struct mrb_ast_stmts_node*)n;
+ node *last = stmts->stmts;
+ if (last) {
+ /* Find the last statement in the cons list */
+ while (last->cdr) {
+ last = last->cdr;
+ }
+ void_expr_error(p, last->car);
+ }
+ }
+ return;
+ case NODE_BEGIN:
+ {
+ struct mrb_ast_begin_node *begin_n = (struct mrb_ast_begin_node*)n;
+ if (begin_n->body) {
+ void_expr_error(p, (node*)begin_n->body);
+ }
+ }
+ return;
+ default:
+ /* Other variable-sized nodes are OK */
+ return;
+ }
+ }
+
+ /* Should not reach here - all nodes should be variable-sized now */
+}
+
+static void pushback(parser_state *p, int c);
+static mrb_bool peeks(parser_state *p, const char *s);
+static mrb_bool skips(parser_state *p, const char *s);
+
+static inline int
+nextc0(parser_state *p)
+{
+ if (p->s && p->s < p->send) {
+ return (unsigned char)*p->s++;
+ }
+ else {
+#ifndef MRB_NO_STDIO
+ int c;
+
+ if (p->f) {
+ c = fgetc(p->f);
+ if (!feof(p->f)) return c;
+ }
+#endif
+ return -1;
+ }
+}
+
+static inline int
+nextc(parser_state *p)
+{
+ int c;
+
+ if (p->pb) {
+ node *tmp;
+
+ c = node_to_int(p->pb->car);
+ tmp = p->pb;
+ p->pb = p->pb->cdr;
+ cons_free(tmp);
+ }
+ else {
+ c = nextc0(p);
+ if (c < 0) goto eof;
+ }
+ if (c >= 0) {
+ p->column++;
+ }
+ if (c == '\r') {
+ const int lf = nextc0(p);
+ if (lf == '\n') {
+ return '\n';
+ }
+ if (lf > 0) pushback(p, lf);
+ }
+ return c;
+
+ eof:
+ if (!p->cxt) return -1;
+ else {
+ if (p->cxt->partial_hook(p) < 0)
+ return -1; /* end of program(s) */
+ return -2; /* end of a file in the program files */
+ }
+}
+
+static void
+pushback(parser_state *p, int c)
+{
+ if (c >= 0) {
+ p->column--;
+ }
+ p->pb = cons(int_to_node(c), p->pb);
+}
+
+static void
+skip(parser_state *p, char term)
+{
+ int c;
+
+ for (;;) {
+ c = nextc(p);
+ if (c < 0) break;
+ if (c == term) break;
+ }
+}
+
+static int
+peekc_n(parser_state *p, int n)
+{
+ node *list = 0;
+ int c0;
+
+ do {
+ c0 = nextc(p);
+ if (c0 == -1) return c0; /* do not skip partial EOF */
+ if (c0 >= 0) --p->column;
+ list = push(list, int_to_node(c0));
+ } while(n--);
+ if (p->pb) {
+ p->pb = append(list, p->pb);
+ }
+ else {
+ p->pb = list;
+ }
+ return c0;
+}
+
+static mrb_bool
+peek_n(parser_state *p, int c, int n)
+{
+ return peekc_n(p, n) == c && c >= 0;
+}
+#define peek(p,c) peek_n((p), (c), 0)
+
+static mrb_bool
+peeks(parser_state *p, const char *s)
+{
+ size_t len = strlen(s);
+
+#ifndef MRB_NO_STDIO
+ if (p->f) {
+ int n = 0;
+ while (*s) {
+ if (!peek_n(p, *s++, n++)) return FALSE;
+ }
+ return TRUE;
+ }
+ else
+#endif
+ if (p->s && p->s + len <= p->send) {
+ if (memcmp(p->s, s, len) == 0) return TRUE;
+ }
+ return FALSE;
+}
+
+static mrb_bool
+skips(parser_state *p, const char *s)
+{
+ int c;
+
+ for (;;) {
+ /* skip until first char */
+ for (;;) {
+ c = nextc(p);
+ if (c < 0) return FALSE;
+ if (c == '\n') {
+ p->lineno++;
+ p->column = 0;
+ }
+ if (c == *s) break;
+ }
+ s++;
+ if (peeks(p, s)) {
+ size_t len = strlen(s);
+
+ while (len--) {
+ if (nextc(p) == '\n') {
+ p->lineno++;
+ p->column = 0;
+ }
+ }
+ return TRUE;
+ }
+ else {
+ s--;
+ }
+ }
+ return FALSE;
+}
+
+static int
+newtok(parser_state *p)
+{
+ if (p->tokbuf != p->buf) {
+ mrbc_free(p->tokbuf);
+ p->tokbuf = p->buf;
+ p->tsiz = MRB_PARSER_TOKBUF_SIZE;
+ }
+ p->tidx = 0;
+ return p->column - 1;
+}
+
+static void
+tokadd(parser_state *p, int32_t c)
+{
+ char utf8[4];
+ int i, len;
+
+ /* mrb_assert(-0x10FFFF <= c && c <= 0xFF); */
+ if (c >= 0) {
+ /* Single byte from source or non-Unicode escape */
+ utf8[0] = (char)c;
+ len = 1;
+ }
+ else {
+ /* Unicode character (negative c indicates codepoint) */
+ len = (int)mrb_utf8_to_buf(utf8, (uint32_t)(-c));
+ }
+ 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*)mrbc_malloc(p->tsiz);
+ memcpy(p->tokbuf, p->buf, MRB_PARSER_TOKBUF_SIZE);
+ }
+ else {
+ p->tokbuf = (char*)mrbc_realloc(p->tokbuf, p->tsiz);
+ }
+ }
+ for (i = 0; i < len; i++) {
+ p->tokbuf[p->tidx++] = utf8[i];
+ }
+}
+
+static int
+toklast(parser_state *p)
+{
+ return p->tokbuf[p->tidx-1];
+}
+
+static void
+tokfix(parser_state *p)
+{
+ if (p->tidx >= MRB_PARSER_TOKBUF_MAX) {
+ p->tidx = MRB_PARSER_TOKBUF_MAX-1;
+ yyerror(NULL, p, "string too long (truncated)");
+ }
+ p->tokbuf[p->tidx] = '\0';
+}
+
+static const char*
+tok(parser_state *p)
+{
+ return p->tokbuf;
+}
+
+static int
+toklen(parser_state *p)
+{
+ return p->tidx;
+}
+
+#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() || p->lstate == EXPR_VALUE)
+#define IS_LABEL_SUFFIX(n) (peek_n(p, ':',(n)) && !peek_n(p, ':', (n)+1))
+
+static int32_t
+scan_oct(const int *start, int len, int *retlen)
+{
+ const int *s = start;
+ int32_t retval = 0;
+
+ /* mrb_assert(len <= 3) */
+ while (len-- && *s >= '0' && *s <= '7') {
+ retval <<= 3;
+ retval |= *s++ - '0';
+ }
+ *retlen = (int)(s - start);
+
+ return retval;
+}
+
+static int32_t
+scan_hex(parser_state *p, const int *start, int len, int *retlen)
+{
+ static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
+ const int *s = start;
+ uint32_t retval = 0;
+ char *tmp;
+
+ /* mrb_assert(len <= 8) */
+ while (len-- && *s && (tmp = (char*)strchr(hexdigit, *s))) {
+ retval <<= 4;
+ retval |= (tmp - hexdigit) & 15;
+ s++;
+ }
+ *retlen = (int)(s - start);
+
+ return (int32_t)retval;
+}
+
+static int32_t
+read_escape_unicode(parser_state *p, int limit)
+{
+ int buf[9];
+ int i;
+ int32_t hex;
+
+ /* Look for opening brace */
+ i = 0;
+ buf[0] = nextc(p);
+ if (buf[0] < 0) {
+ eof:
+ yyerror(NULL, p, "invalid escape character syntax");
+ return -1;
+ }
+ 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]);
+ }
+ hex = scan_hex(p, buf, i, &i);
+ if (i == 0 || hex > 0x10FFFF || (hex & 0xFFFFF800) == 0xD800) {
+ yyerror(NULL, p, "invalid Unicode code point");
+ return -1;
+ }
+ return hex;
+}
+
+/* Return negative to indicate Unicode code point */
+static int32_t
+read_escape(parser_state *p)
+{
+ int32_t c;
+
+ switch (c = nextc(p)) {
+ case '\\':/* Backslash */
+ return c;
+
+ case 'n':/* newline */
+ return '\n';
+
+ case 't':/* horizontal tab */
+ return '\t';
+
+ case 'r':/* carriage-return */
+ return '\r';
+
+ case 'f':/* form-feed */
+ return '\f';
+
+ case 'v':/* vertical tab */
+ return '\13';
+
+ case 'a':/* alarm(bell) */
+ return '\007';
+
+ case 'e':/* escape */
+ return 033;
+
+ case '0': case '1': case '2': case '3': /* octal constant */
+ case '4': case '5': case '6': case '7':
+ {
+ int buf[3];
+ int i;
+
+ buf[0] = c;
+ for (i=1; i<3; i++) {
+ buf[i] = nextc(p);
+ if (buf[i] < 0) goto eof;
+ if (buf[i] < '0' || '7' < buf[i]) {
+ pushback(p, buf[i]);
+ break;
+ }
+ }
+ c = scan_oct(buf, i, &i);
+ }
+ return c;
+
+ case 'x': /* hex constant */
+ {
+ int buf[2];
+ int i;
+
+ for (i=0; i<2; i++) {
+ buf[i] = nextc(p);
+ if (buf[i] < 0) goto eof;
+ if (!ISXDIGIT(buf[i])) {
+ pushback(p, buf[i]);
+ break;
+ }
+ }
+ if (i == 0) {
+ yyerror(NULL, p, "invalid hex escape");
+ return -1;
+ }
+ return scan_hex(p, buf, i, &i);
+ }
+
+ case 'u': /* Unicode */
+ if (peek(p, '{')) {
+ /* \u{xxxxxxxx} form */
+ nextc(p);
+ c = read_escape_unicode(p, 8);
+ if (c < 0) return 0;
+ if (nextc(p) != '}') goto eof;
+ }
+ else {
+ c = read_escape_unicode(p, 4);
+ if (c < 0) return 0;
+ }
+ return -c;
+
+ case 'b':/* backspace */
+ return '\010';
+
+ case 's':/* space */
+ return ' ';
+
+ case 'M':
+ if ((c = nextc(p)) != '-') {
+ yyerror(NULL, p, "Invalid escape character syntax");
+ pushback(p, c);
+ return '\0';
+ }
+ if ((c = nextc(p)) == '\\') {
+ return read_escape(p) | 0x80;
+ }
+ else if (c < 0) goto eof;
+ else {
+ return ((c & 0xff) | 0x80);
+ }
+
+ case 'C':
+ if ((c = nextc(p)) != '-') {
+ yyerror(NULL, p, "Invalid escape character syntax");
+ pushback(p, c);
+ return '\0';
+ }
+ case 'c':
+ if ((c = nextc(p))== '\\') {
+ c = read_escape(p);
+ }
+ else if (c == '?')
+ return 0177;
+ else if (c < 0) goto eof;
+ return c & 0x9f;
+
+ eof:
+ case -1:
+ case -2: /* end of a file */
+ yyerror(NULL, p, "Invalid escape character syntax");
+ return '\0';
+
+ default:
+ return c;
+ }
+}
+
+static void
+heredoc_count_indent(parser_heredoc_info *hinfo, const char *str, size_t len, size_t spaces, size_t *offset)
+{
+ size_t indent = 0;
+ *offset = 0;
+ for (size_t i = 0; i < len; i++) {
+ size_t size;
+ if (str[i] == '\n')
+ break;
+ else if (str[i] == '\t')
+ size = 8;
+ else if (ISSPACE(str[i]))
+ size = 1;
+ else
+ break;
+ size_t nindent = indent + size;
+ if (nindent > spaces || nindent > hinfo->indent)
+ break;
+ indent = nindent;
+ *offset += 1;
+ }
+}
+
+static void
+heredoc_remove_indent(parser_state *p, parser_heredoc_info *hinfo)
+{
+ if (!hinfo->remove_indent || hinfo->indent == 0)
+ return;
+ node *indented, *n, *pair, *escaped, *nspaces;
+ const char *str;
+ size_t len, spaces, offset, start, end;
+ indented = hinfo->indented;
+ while (indented) {
+ n = indented->car;
+ pair = n->car;
+ len = (size_t)pair->car;
+ str = (char*)pair->cdr;
+ escaped = n->cdr->car;
+ nspaces = n->cdr->cdr;
+ if (escaped) {
+ char *newstr = strndup(str, len);
+ size_t newlen = 0;
+ start = 0;
+ while (start < len) {
+ end = escaped ? (size_t)escaped->car : len;
+ if (end > len) end = len;
+ spaces = (size_t)nspaces->car;
+ size_t esclen = end - start;
+ heredoc_count_indent(hinfo, str + start, esclen, spaces, &offset);
+ esclen -= offset;
+ memcpy(newstr + newlen, str + start + offset, esclen);
+ newlen += esclen;
+ start = end;
+ if (escaped)
+ escaped = escaped->cdr;
+ nspaces = nspaces->cdr;
+ }
+ if (newlen < len)
+ newstr[newlen] = '\0';
+ pair->car = (node*)newlen;
+ pair->cdr = (node*)newstr;
+ }
+ else {
+ spaces = (size_t)nspaces->car;
+ heredoc_count_indent(hinfo, str, len, spaces, &offset);
+ pair->car = (node*)(len - offset);
+ pair->cdr = (node*)(str + offset);
+ }
+ indented = indented->cdr;
+ }
+}
+
+static void
+heredoc_push_indented(parser_state *p, parser_heredoc_info *hinfo, node *pair, node *escaped, node *nspaces, mrb_bool empty_line)
+{
+ hinfo->indented = push(hinfo->indented, cons(pair, cons(escaped, nspaces)));
+ while (nspaces) {
+ size_t tspaces = (size_t)nspaces->car;
+ if ((hinfo->indent == ~0U || tspaces < hinfo->indent) && !empty_line)
+ hinfo->indent = tspaces;
+ nspaces = nspaces->cdr;
+ }
+}
+
+static int
+parse_string(parser_state *p)
+{
+ int c;
+ string_type type = (string_type)p->lex_strterm->type;
+ int nest_level = p->lex_strterm->level;
+ int beg = p->lex_strterm->paren;
+ int end = p->lex_strterm->term;
+ parser_heredoc_info *hinfo = (type & STR_FUNC_HEREDOC) ? parsing_heredoc_info(p) : NULL;
+
+ mrb_bool unindent = hinfo && hinfo->remove_indent;
+ mrb_bool head = hinfo && hinfo->line_head;
+ mrb_bool empty = TRUE;
+ size_t spaces = 0;
+ size_t pos = -1;
+ node *escaped = NULL;
+ node *nspaces = NULL;
+
+ if (beg == 0) beg = -3; /* should never happen */
+ if (end == 0) end = -3;
+ newtok(p);
+ while ((c = nextc(p)) != end || nest_level != 0) {
+ pos++;
+ if (hinfo && (c == '\n' || c < 0)) {
+ mrb_bool line_head;
+ tokadd(p, '\n');
+ tokfix(p);
+ p->lineno++;
+ p->column = 0;
+ line_head = hinfo->line_head;
+ hinfo->line_head = TRUE;
+ if (line_head) {
+ /* check whether end of heredoc */
+ const char *s = tok(p);
+ int len = toklen(p);
+ if (hinfo->allow_indent) {
+ while (ISSPACE(*s) && len > 0) {
+ s++;
+ len--;
+ }
+ }
+ if (hinfo->term_len > 0 && len-1 == hinfo->term_len && strncmp(s, hinfo->term, len-1) == 0) {
+ heredoc_remove_indent(p, hinfo);
+ return tHEREDOC_END;
+ }
+ }
+ if (c < 0) {
+ char buf[256];
+ const char s1[] = "can't find heredoc delimiter \"";
+ const char s2[] = "\" anywhere before EOF";
+
+ if (sizeof(s1)+sizeof(s2)+strlen(hinfo->term)+1 >= sizeof(buf)) {
+ yyerror(NULL, p, "can't find heredoc delimiter anywhere before EOF");
+ }
+ else {
+ strcpy(buf, s1);
+ strcat(buf, hinfo->term);
+ strcat(buf, s2);
+ yyerror(NULL, p, buf);
+ }
+ return 0;
+ }
+ pylval.nd = new_str_tok(p);
+ if (unindent && head) {
+ nspaces = push(nspaces, int_to_node(spaces));
+ heredoc_push_indented(p, hinfo, pylval.nd, escaped, nspaces, empty && line_head);
+ }
+ return tHD_STRING_MID;
+ }
+ if (unindent && empty) {
+ if (c == '\t')
+ spaces += 8;
+ else if (ISSPACE(c))
+ spaces++;
+ else
+ empty = FALSE;
+ }
+ if (c < 0) {
+ yyerror(NULL, p, "unterminated string meets end of file");
+ return 0;
+ }
+ else if (c == beg) {
+ nest_level++;
+ p->lex_strterm->level = nest_level;
+ }
+ else if (c == end) {
+ nest_level--;
+ p->lex_strterm->level = nest_level;
+ }
+ else if (c == '\\') {
+ c = nextc(p);
+ if (type & STR_FUNC_EXPAND) {
+ if (c == end || c == beg) {
+ tokadd(p, c);
+ }
+ else if (c == '\n') {
+ p->lineno++;
+ p->column = 0;
+ if (unindent) {
+ nspaces = push(nspaces, int_to_node(spaces));
+ escaped = push(escaped, int_to_node(pos));
+ pos--;
+ empty = TRUE;
+ spaces = 0;
+ }
+ if (type & STR_FUNC_ARRAY) {
+ tokadd(p, '\n');
+ }
+ }
+ else if (type & STR_FUNC_REGEXP) {
+ tokadd(p, '\\');
+ tokadd(p, c);
+ }
+ else if (c == 'u' && peek(p, '{')) {
+ /* \u{xxxx xxxx xxxx} form */
+ nextc(p);
+ while (1) {
+ do c = nextc(p); while (ISSPACE(c));
+ if (c == '}') break;
+ pushback(p, c);
+ c = read_escape_unicode(p, 8);
+ if (c < 0) break;
+ tokadd(p, -c);
+ }
+ if (hinfo)
+ hinfo->line_head = FALSE;
+ }
+ else {
+ pushback(p, c);
+ tokadd(p, read_escape(p));
+ if (hinfo)
+ hinfo->line_head = FALSE;
+ }
+ }
+ else {
+ if (c != beg && c != end) {
+ if (c == '\n') {
+ p->lineno++;
+ p->column = 0;
+ }
+ if (!(c == '\\' || ((type & STR_FUNC_ARRAY) && ISSPACE(c)))) {
+ tokadd(p, '\\');
+ }
+ }
+ tokadd(p, c);
+ }
+ continue;
+ }
+ else if ((c == '#') && (type & STR_FUNC_EXPAND)) {
+ c = nextc(p);
+ if (c == '{') {
+ tokfix(p);
+ p->lstate = EXPR_BEG;
+ p->cmd_start = TRUE;
+ pylval.nd = new_str_tok(p);
+ if (hinfo) {
+ if (unindent && head) {
+ nspaces = push(nspaces, int_to_node(spaces));
+ heredoc_push_indented(p, hinfo, pylval.nd, escaped, nspaces, FALSE);
+ }
+ hinfo->line_head = FALSE;
+ return tHD_STRING_PART;
+ }
+ return tSTRING_PART;
+ }
+ tokadd(p, '#');
+ pushback(p, c);
+ continue;
+ }
+ if ((type & STR_FUNC_ARRAY) && ISSPACE(c)) {
+ if (toklen(p) == 0) {
+ do {
+ if (c == '\n') {
+ p->lineno++;
+ p->column = 0;
+ heredoc_treat_nextline(p);
+ if (p->parsing_heredoc != NULL) {
+ return tHD_LITERAL_DELIM;
+ }
+ }
+ c = nextc(p);
+ } while (ISSPACE(c));
+ pushback(p, c);
+ return tLITERAL_DELIM;
+ }
+ else {
+ pushback(p, c);
+ tokfix(p);
+ pylval.nd = new_str_tok(p);
+ return tSTRING_MID;
+ }
+ }
+ if (c == '\n') {
+ p->lineno++;
+ p->column = 0;
+ }
+ tokadd(p, c);
+ }
+
+ tokfix(p);
+ p->lstate = EXPR_END;
+ end_strterm(p);
+
+ if (type & STR_FUNC_XQUOTE) {
+ pylval.nd = new_str_tok(p);
+ return tXSTRING;
+ }
+
+ if (type & STR_FUNC_REGEXP) {
+ int f = 0;
+ int re_opt;
+ int pattern_len = toklen(p);
+ char *s = strndup(tok(p), pattern_len);
+ char flags[3];
+ char *flag = flags;
+ char enc = '\0';
+ char *encp;
+ char *dup;
+
+ newtok(p);
+ while (re_opt = nextc(p), re_opt >= 0 && ISALPHA(re_opt)) {
+ switch (re_opt) {
+ case 'i': f |= 1; break;
+ case 'x': f |= 2; break;
+ case 'm': f |= 4; break;
+ case 'u': f |= 16; break;
+ case 'n': f |= 32; break;
+ case 'o': break;
+ default: tokadd(p, re_opt); break;
+ }
+ }
+ pushback(p, re_opt);
+ if (toklen(p)) {
+ char msg[128];
+
+ strcpy(msg, "unknown regexp option");
+ tokfix(p);
+ if (toklen(p) > 1) {
+ strcat(msg, "s");
+ }
+ strcat(msg, " - ");
+ strncat(msg, tok(p), sizeof(msg) - strlen(msg) - 1);
+ yyerror(NULL, p, msg);
+ }
+ if (f != 0) {
+ if (f & 1) *flag++ = 'i';
+ if (f & 2) *flag++ = 'x';
+ if (f & 4) *flag++ = 'm';
+ if (f & 16) enc = 'u';
+ if (f & 32) enc = 'n';
+ }
+ if (flag > flags) {
+ dup = strndup(flags, (size_t)(flag - flags));
+ }
+ else {
+ dup = NULL;
+ }
+ if (enc) {
+ encp = strndup(&enc, 1);
+ }
+ else {
+ encp = NULL;
+ }
+ pylval.nd = cons(cons(int_to_node(pattern_len), (node*)s), cons((node*)dup, (node*)encp));
+
+ return tREGEXP;
+ }
+ pylval.nd = new_str_tok(p);
+
+ return tSTRING;
+}
+
+static int
+number_literal_suffix(parser_state *p)
+{
+ int c, result = 0;
+ node *list = 0;
+ int column = p->column;
+ int mask = NUM_SUFFIX_R|NUM_SUFFIX_I;
+
+ while ((c = nextc(p)) != -1) {
+ list = push(list, int_to_node(c));
+
+ if ((mask & NUM_SUFFIX_I) && c == 'i') {
+ result |= (mask & NUM_SUFFIX_I);
+ mask &= ~NUM_SUFFIX_I;
+ /* r after i, rational of complex is disallowed */
+ mask &= ~NUM_SUFFIX_R;
+ continue;
+ }
+ if ((mask & NUM_SUFFIX_R) && c == 'r') {
+ result |= (mask & NUM_SUFFIX_R);
+ mask &= ~NUM_SUFFIX_R;
+ continue;
+ }
+ if (!ISASCII(c) || ISALPHA(c) || c == '_') {
+ p->column = column;
+ if (p->pb) {
+ p->pb = append(list, p->pb);
+ }
+ else {
+ p->pb = list;
+ }
+ return 0;
+ }
+ pushback(p, c);
+ break;
+ }
+ return result;
+}
+
+static int
+heredoc_identifier(parser_state *p)
+{
+ int c;
+ int type = str_heredoc;
+ mrb_bool indent = FALSE;
+ mrb_bool squiggly = FALSE;
+ mrb_bool quote = FALSE;
+ node *newnode;
+ parser_heredoc_info *info;
+
+ c = nextc(p);
+ if (ISSPACE(c) || c == '=') {
+ pushback(p, c);
+ return 0;
+ }
+ if (c == '-' || c == '~') {
+ if (c == '-')
+ indent = TRUE;
+ if (c == '~')
+ squiggly = TRUE;
+ c = nextc(p);
+ }
+ if (c == '\'' || c == '"') {
+ int term = c;
+ if (c == '\'')
+ quote = TRUE;
+ newtok(p);
+ while ((c = nextc(p)) >= 0 && c != term) {
+ if (c == '\n') {
+ c = -1;
+ break;
+ }
+ tokadd(p, c);
+ }
+ if (c < 0) {
+ yyerror(NULL, p, "unterminated here document identifier");
+ return 0;
+ }
+ }
+ else {
+ if (c < 0) {
+ return 0; /* missing here document identifier */
+ }
+ if (! identchar(c)) {
+ pushback(p, c);
+ if (indent) pushback(p, '-');
+ if (squiggly) pushback(p, '~');
+ return 0;
+ }
+ newtok(p);
+ do {
+ tokadd(p, c);
+ } while ((c = nextc(p)) >= 0 && identchar(c));
+ pushback(p, c);
+ }
+ tokfix(p);
+ newnode = new_heredoc(p, &info);
+ info->term = strndup(tok(p), toklen(p));
+ info->term_len = toklen(p);
+ if (! quote)
+ type |= STR_FUNC_EXPAND;
+ info->type = (string_type)type;
+ info->allow_indent = indent || squiggly;
+ info->remove_indent = squiggly;
+ info->indent = ~0U;
+ info->indented = NULL;
+ info->line_head = TRUE;
+ info->doc = NULL;
+ p->heredocs_from_nextline = push(p->heredocs_from_nextline, newnode);
+ p->lstate = EXPR_END;
+
+ pylval.nd = newnode;
+ return tHEREDOC_BEG;
+}
+
+static int
+arg_ambiguous(parser_state *p)
+{
+ yywarning(p, "ambiguous first argument; put parentheses or even spaces");
+ return 1;
+}
+
+#include "lex.def"
+
+static int
+parser_yylex(parser_state *p)
+{
+ int32_t c;
+ int nlines = 1;
+ int space_seen = 0;
+ int cmd_state;
+ enum mrb_lex_state_enum last_state;
+ int token_column;
+
+ /* Early termination if too many errors - prevents DoS from malformed input */
+ if (p->nerr > 10) {
+ return 0; /* EOF */
+ }
+
+ if (p->lex_strterm) {
+ if (is_strterm_type(p, STR_FUNC_HEREDOC)) {
+ if (p->parsing_heredoc != NULL)
+ return parse_string(p);
+ }
+ else
+ return parse_string(p);
+ }
+ cmd_state = p->cmd_start;
+ p->cmd_start = FALSE;
+ retry:
+ last_state = p->lstate;
+ switch (c = nextc(p)) {
+ case '\004': /* ^D */
+ case '\032': /* ^Z */
+ case '\0': /* NUL */
+ case -1: /* end of script. */
+ if (p->heredocs_from_nextline)
+ goto maybe_heredoc;
+ return 0;
+
+ /* white spaces */
+ case ' ': case '\t': case '\f': case '\r':
+ case '\13': /* '\v' */
+ space_seen = 1;
+ goto retry;
+
+ case '#': /* it's a comment */
+ skip(p, '\n');
+ /* fall through */
+ case -2: /* end of a file */
+ case '\n':
+ maybe_heredoc:
+ heredoc_treat_nextline(p);
+ p->column = 0;
+ switch (p->lstate) {
+ case EXPR_BEG:
+ case EXPR_FNAME:
+ case EXPR_DOT:
+ case EXPR_CLASS:
+ case EXPR_VALUE:
+ p->lineno++;
+ if (p->parsing_heredoc != NULL) {
+ if (p->lex_strterm) {
+ return parse_string(p);
+ }
+ }
+ goto retry;
+ default:
+ break;
+ }
+ if (p->parsing_heredoc != NULL) {
+ pylval.num = nlines;
+ return '\n';
+ }
+ while ((c = nextc(p))) {
+ switch (c) {
+ case ' ': case '\t': case '\f': case '\r':
+ case '\13': /* '\v' */
+ space_seen = 1;
+ break;
+ case '#': /* comment as a whitespace */
+ skip(p, '\n');
+ nlines++;
+ break;
+ case '.':
+ if (!peek(p, '.')) {
+ pushback(p, '.');
+ p->lineno+=nlines; nlines=1;
+ goto retry;
+ }
+ pushback(p, c);
+ goto normal_newline;
+ case '&':
+ if (peek(p, '.')) {
+ pushback(p, '&');
+ p->lineno+=nlines; nlines=1;
+ goto retry;
+ }
+ pushback(p, c);
+ goto normal_newline;
+ case -1: /* EOF */
+ case -2: /* end of a file */
+ goto normal_newline;
+ default:
+ pushback(p, c);
+ goto normal_newline;
+ }
+ }
+ normal_newline:
+ p->cmd_start = TRUE;
+ p->lstate = EXPR_BEG;
+ pylval.num = nlines;
+ return '\n';
+
+ case '*':
+ if ((c = nextc(p)) == '*') {
+ if ((c = nextc(p)) == '=') {
+ pylval.id = intern_op(pow);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ if (IS_SPCARG(c)) {
+ yywarning(p, "'**' interpreted as argument prefix");
+ c = tDSTAR;
+ }
+ else if (IS_BEG()) {
+ c = tDSTAR;
+ }
+ else {
+ c = tPOW; /* "**", "argument prefix" */
+ }
+ }
+ else {
+ if (c == '=') {
+ pylval.id = intern_op(mul);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ if (IS_SPCARG(c)) {
+ yywarning(p, "'*' interpreted as argument prefix");
+ c = tSTAR;
+ }
+ else if (IS_BEG()) {
+ c = tSTAR;
+ }
+ else {
+ c = '*';
+ }
+ }
+ if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
+ p->lstate = EXPR_ARG;
+ }
+ else {
+ p->lstate = EXPR_BEG;
+ }
+ return c;
+
+ case '!':
+ c = nextc(p);
+ if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
+ p->lstate = EXPR_ARG;
+ if (c == '@') {
+ return '!';
+ }
+ }
+ else {
+ p->lstate = EXPR_BEG;
+ }
+ if (c == '=') {
+ return tNEQ;
+ }
+ if (c == '~') {
+ return tNMATCH;
+ }
+ pushback(p, c);
+ return '!';
+
+ case '=':
+ if (p->column == 1) {
+ static const char begin[] = "begin";
+ static const char end[] = "\n=end";
+ if (peeks(p, begin)) {
+ c = peekc_n(p, sizeof(begin)-1);
+ if (c < 0 || ISSPACE(c)) {
+ do {
+ if (!skips(p, end)) {
+ yyerror(NULL, p, "embedded document meets end of file");
+ return 0;
+ }
+ c = nextc(p);
+ } while (!(c < 0 || ISSPACE(c)));
+ if (c != '\n') skip(p, '\n');
+ p->lineno+=nlines; nlines=1;
+ p->column = 0;
+ goto retry;
+ }
+ }
+ }
+ if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
+ p->lstate = EXPR_ARG;
+ }
+ else {
+ p->lstate = EXPR_BEG;
+ }
+ if ((c = nextc(p)) == '=') {
+ if ((c = nextc(p)) == '=') {
+ return tEQQ;
+ }
+ pushback(p, c);
+ return tEQ;
+ }
+ if (c == '~') {
+ return tMATCH;
+ }
+ else if (c == '>') {
+ return tASSOC;
+ }
+ pushback(p, c);
+ return '=';
+
+ case '<':
+ c = nextc(p);
+ if (c == '<' &&
+ p->lstate != EXPR_DOT &&
+ p->lstate != EXPR_CLASS &&
+ !IS_END() &&
+ (!IS_ARG() || space_seen)) {
+ int token = heredoc_identifier(p);
+ if (token)
+ return token;
+ }
+ if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
+ p->lstate = EXPR_ARG;
+ }
+ else {
+ p->lstate = EXPR_BEG;
+ if (p->lstate == EXPR_CLASS) {
+ p->cmd_start = TRUE;
+ }
+ }
+ if (c == '=') {
+ if ((c = nextc(p)) == '>') {
+ return tCMP;
+ }
+ pushback(p, c);
+ return tLEQ;
+ }
+ if (c == '<') {
+ if ((c = nextc(p)) == '=') {
+ pylval.id = intern_op(lshift);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ return tLSHFT;
+ }
+ pushback(p, c);
+ return '<';
+
+ case '>':
+ if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
+ p->lstate = EXPR_ARG;
+ }
+ else {
+ p->lstate = EXPR_BEG;
+ }
+ if ((c = nextc(p)) == '=') {
+ return tGEQ;
+ }
+ if (c == '>') {
+ if ((c = nextc(p)) == '=') {
+ pylval.id = intern_op(rshift);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ return tRSHFT;
+ }
+ pushback(p, c);
+ return '>';
+
+ case '"':
+ p->lex_strterm = new_strterm(p, str_dquote, '"', 0);
+ return tSTRING_BEG;
+
+ case '\'':
+ p->lex_strterm = new_strterm(p, str_squote, '\'', 0);
+ return parse_string(p);
+
+ case '`':
+ if (p->lstate == EXPR_FNAME) {
+ p->lstate = EXPR_ENDFN;
+ return '`';
+ }
+ if (p->lstate == EXPR_DOT) {
+ if (cmd_state)
+ p->lstate = EXPR_CMDARG;
+ else
+ p->lstate = EXPR_ARG;
+ return '`';
+ }
+ p->lex_strterm = new_strterm(p, str_xquote, '`', 0);
+ return tXSTRING_BEG;
+
+ case '?':
+ if (IS_END()) {
+ p->lstate = EXPR_VALUE;
+ return '?';
+ }
+ c = nextc(p);
+ if (c < 0) {
+ yyerror(NULL, p, "incomplete character syntax");
+ return 0;
+ }
+ if (ISSPACE(c)) {
+ if (!IS_ARG()) {
+ int c2;
+ switch (c) {
+ case ' ':
+ c2 = 's';
+ break;
+ case '\n':
+ c2 = 'n';
+ break;
+ case '\t':
+ c2 = 't';
+ break;
+ case '\v':
+ c2 = 'v';
+ break;
+ case '\r':
+ c2 = 'r';
+ break;
+ case '\f':
+ c2 = 'f';
+ break;
+ default:
+ c2 = 0;
+ break;
+ }
+ if (c2) {
+ char buf[256];
+ char cc[] = { (char)c2, '\0' };
+
+ strcpy(buf, "invalid character syntax; use ?\\");
+ strncat(buf, cc, 2);
+ yyerror(NULL, p, buf);
+ }
+ }
+ ternary:
+ pushback(p, c);
+ p->lstate = EXPR_VALUE;
+ return '?';
+ }
+ newtok(p);
+ /* need support UTF-8 if configured */
+ if ((ISALNUM(c) || c == '_')) {
+ int c2 = nextc(p);
+ pushback(p, c2);
+ if ((ISALNUM(c2) || c2 == '_')) {
+ goto ternary;
+ }
+ }
+ if (c == '\\') {
+ c = read_escape(p);
+ tokadd(p, c);
+ }
+ else {
+ tokadd(p, c);
+ }
+ tokfix(p);
+ pylval.nd = new_str_tok(p);
+ p->lstate = EXPR_END;
+ return tCHAR;
+
+ case '&':
+ if ((c = nextc(p)) == '&') {
+ p->lstate = EXPR_BEG;
+ if ((c = nextc(p)) == '=') {
+ pylval.id = intern_op(andand);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ return tANDOP;
+ }
+ else if (c == '.') {
+ p->lstate = EXPR_DOT;
+ return tANDDOT;
+ }
+ else if (c == '=') {
+ pylval.id = intern_op(and);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ if (IS_SPCARG(c)) {
+ yywarning(p, "'&' interpreted as argument prefix");
+ c = tAMPER;
+ }
+ else if (IS_BEG()) {
+ c = tAMPER;
+ }
+ else {
+ c = '&';
+ }
+ if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
+ p->lstate = EXPR_ARG;
+ }
+ else {
+ p->lstate = EXPR_BEG;
+ }
+ return c;
+
+ case '|':
+ if ((c = nextc(p)) == '|') {
+ p->lstate = EXPR_BEG;
+ if ((c = nextc(p)) == '=') {
+ pylval.id = intern_op(oror);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ return tOROP;
+ }
+ if (c == '=') {
+ pylval.id = intern_op(or);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
+ }
+ if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
+ p->lstate = EXPR_ARG;
+ }
+ else {
+ p->lstate = EXPR_BEG;
+ }
+ pushback(p, c);
+ return '|';
+
+ case '+':
+ c = nextc(p);
+ if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
+ p->lstate = EXPR_ARG;
+ if (c == '@') {
+ return tUPLUS;
+ }
+ pushback(p, c);
+ return '+';
+ }
+ if (c == '=') {
+ pylval.id = intern_op(add);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
+ }
+ if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) {
+ p->lstate = EXPR_BEG;
+ pushback(p, c);
+ if (c >= 0 && ISDIGIT(c)) {
+ c = '+';
+ goto start_num;
+ }
+ return tUPLUS;
+ }
+ p->lstate = EXPR_BEG;
+ pushback(p, c);
+ return '+';
+
+ case '-':
+ c = nextc(p);
+ if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
+ p->lstate = EXPR_ARG;
+ if (c == '@') {
+ return tUMINUS;
+ }
+ pushback(p, c);
+ return '-';
+ }
+ if (c == '=') {
+ pylval.id = intern_op(sub);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
+ }
+ if (c == '>') {
+ p->lstate = EXPR_ENDFN;
+ return tLAMBDA;
+ }
+ if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) {
+ p->lstate = EXPR_BEG;
+ pushback(p, c);
+ if (c >= 0 && ISDIGIT(c)) {
+ return tUMINUS_NUM;
+ }
+ return tUMINUS;
+ }
+ p->lstate = EXPR_BEG;
+ pushback(p, c);
+ return '-';
+
+ case '.':
+ {
+ int is_beg = IS_BEG();
+ p->lstate = EXPR_MID;
+ if ((c = nextc(p)) == '.') {
+ if ((c = nextc(p)) == '.') {
+ return is_beg ? tBDOT3 : tDOT3;
+ }
+ pushback(p, c);
+ return is_beg ? tBDOT2 : tDOT2;
+ }
+ pushback(p, c);
+ p->lstate = EXPR_BEG;
+ if (c >= 0 && ISDIGIT(c)) {
+ yyerror(NULL, p, "no .<digit> floating literal anymore; put 0 before dot");
+ }
+ p->lstate = EXPR_DOT;
+ return '.';
+ }
+
+ start_num:
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ int is_float, seen_point, seen_e, nondigit;
+ int suffix = 0;
+
+ is_float = seen_point = seen_e = nondigit = 0;
+ p->lstate = EXPR_END;
+ newtok(p);
+ if (c == '-') {
+ tokadd(p, c);
+ c = nextc(p);
+ }
+ else if (c == '+') {
+ c = nextc(p);
+ }
+ if (c == '0') {
+#define no_digits() do {yyerror(NULL, p,"numeric literal without digits"); return 0;} while (0)
+ int start = toklen(p);
+ c = nextc(p);
+ if (c == 'x' || c == 'X') {
+ /* hexadecimal */
+ c = nextc(p);
+ if (c >= 0 && ISXDIGIT(c)) {
+ do {
+ if (c == '_') {
+ if (nondigit) break;
+ nondigit = c;
+ continue;
+ }
+ if (!ISXDIGIT(c)) break;
+ nondigit = 0;
+ tokadd(p, tolower(c));
+ } while ((c = nextc(p)) >= 0);
+ }
+ pushback(p, c);
+ tokfix(p);
+ if (toklen(p) == start) {
+ no_digits();
+ }
+ else if (nondigit) goto trailing_uc;
+ suffix = number_literal_suffix(p);
+ pylval.nd = new_int(p, tok(p), 16, suffix);
+ 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;
+ suffix = number_literal_suffix(p);
+ pylval.nd = new_int(p, tok(p), 2, suffix);
+ 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;
+ suffix = number_literal_suffix(p);
+ pylval.nd = new_int(p, tok(p), 10, suffix);
+ 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;
+ suffix = number_literal_suffix(p);
+ pylval.nd = new_int(p, tok(p), 8, suffix);
+ return tINTEGER;
+ }
+ if (nondigit) {
+ pushback(p, c);
+ goto trailing_uc;
+ }
+ }
+ if (c > '7' && c <= '9') {
+ invalid_octal:
+ yyerror(NULL, p, "Invalid octal digit");
+ }
+ else if (c == '.' || c == 'e' || c == 'E') {
+ tokadd(p, '0');
+ }
+ else {
+ pushback(p, c);
+ suffix = number_literal_suffix(p);
+ pylval.nd = new_int(p, "0", 10, suffix);
+ return tINTEGER;
+ }
+ }
+
+ for (;;) {
+ switch (c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ nondigit = 0;
+ tokadd(p, c);
+ break;
+
+ case '.':
+ if (nondigit) goto trailing_uc;
+ if (seen_point || seen_e) {
+ goto decode_num;
+ }
+ else {
+ int c0 = nextc(p);
+ if (c0 < 0 || !ISDIGIT(c0)) {
+ pushback(p, c0);
+ goto decode_num;
+ }
+ c = c0;
+ }
+ tokadd(p, '.');
+ tokadd(p, c);
+ is_float++;
+ seen_point++;
+ nondigit = 0;
+ break;
+
+ case 'e':
+ case 'E':
+ if (nondigit) {
+ pushback(p, c);
+ c = nondigit;
+ goto decode_num;
+ }
+ if (seen_e) {
+ goto decode_num;
+ }
+ tokadd(p, c);
+ seen_e++;
+ is_float++;
+ nondigit = c;
+ c = nextc(p);
+ if (c != '-' && c != '+') continue;
+ tokadd(p, c);
+ nondigit = c;
+ break;
+
+ case '_': /* '_' in number just ignored */
+ if (nondigit) goto decode_num;
+ nondigit = c;
+ break;
+
+ default:
+ goto decode_num;
+ }
+ c = nextc(p);
+ }
+
+ decode_num:
+ pushback(p, c);
+ if (nondigit) {
+ trailing_uc:
+ yyerror_c(p, "trailing non digit in number: ", (char)nondigit);
+ }
+ tokfix(p);
+ if (is_float) {
+#ifdef MRB_NO_FLOAT
+ yywarning_s(p, "floating-point numbers are not supported", tok(p));
+ pylval.nd = new_int(p, "0", 10, 0);
+ return tINTEGER;
+#else
+ double d;
+
+ if (!mrb_read_float(tok(p), NULL, &d)) {
+ yywarning_s(p, "corrupted float value", tok(p));
+ }
+ suffix = number_literal_suffix(p);
+ if (seen_e && (suffix & NUM_SUFFIX_R)) {
+ pushback(p, 'r');
+ suffix &= ~NUM_SUFFIX_R;
+ }
+ pylval.nd = new_float(p, tok(p), suffix);
+ return tFLOAT;
+#endif
+ }
+ suffix = number_literal_suffix(p);
+ pylval.nd = new_int(p, tok(p), 10, suffix);
+ return tINTEGER;
+ }
+
+ case ')':
+ case ']':
+ p->paren_nest--;
+ /* fall through */
+ case '}':
+ COND_LEXPOP();
+ CMDARG_LEXPOP();
+ if (c == ')')
+ p->lstate = EXPR_ENDFN;
+ else
+ p->lstate = EXPR_END;
+ return c;
+
+ case ':':
+ c = nextc(p);
+ if (c == ':') {
+ if (IS_BEG() || p->lstate == EXPR_CLASS || IS_SPCARG(-1)) {
+ p->lstate = EXPR_BEG;
+ return tCOLON3;
+ }
+ p->lstate = EXPR_DOT;
+ return tCOLON2;
+ }
+ if (!space_seen && IS_END()) {
+ pushback(p, c);
+ /* In pattern matching context, use EXPR_ARG so newlines are significant */
+ p->lstate = p->in_kwarg ? EXPR_ARG : EXPR_BEG;
+ return tLABEL_TAG;
+ }
+ if (IS_END() || ISSPACE(c) || c == '#') {
+ pushback(p, c);
+ p->lstate = EXPR_BEG;
+ return ':';
+ }
+ pushback(p, c);
+ p->lstate = EXPR_FNAME;
+ return tSYMBEG;
+
+ case '/':
+ if (IS_BEG()) {
+ p->lex_strterm = new_strterm(p, str_regexp, '/', 0);
+ return tREGEXP_BEG;
+ }
+ if ((c = nextc(p)) == '=') {
+ pylval.id = intern_op(div);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ if (IS_SPCARG(c)) {
+ p->lex_strterm = new_strterm(p, str_regexp, '/', 0);
+ return tREGEXP_BEG;
+ }
+ if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
+ p->lstate = EXPR_ARG;
+ }
+ else {
+ p->lstate = EXPR_BEG;
+ }
+ return '/';
+
+ case '^':
+ if ((c = nextc(p)) == '=') {
+ pylval.id = intern_op(xor);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
+ }
+ if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
+ p->lstate = EXPR_ARG;
+ }
+ else {
+ p->lstate = EXPR_BEG;
+ }
+ pushback(p, c);
+ return '^';
+
+ case ';':
+ p->lstate = EXPR_BEG;
+ return ';';
+
+ case ',':
+ p->lstate = EXPR_BEG;
+ return ',';
+
+ case '~':
+ if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
+ if ((c = nextc(p)) != '@') {
+ pushback(p, c);
+ }
+ p->lstate = EXPR_ARG;
+ }
+ else {
+ p->lstate = EXPR_BEG;
+ }
+ return '~';
+
+ case '(':
+ if (IS_BEG()) {
+ c = tLPAREN;
+ }
+ else if (IS_SPCARG(-1)) {
+ c = tLPAREN_ARG;
+ }
+ else if (p->lstate == EXPR_END && space_seen) {
+ 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;
+ p->paren_nest--;
+ if ((c = nextc(p)) == ']') {
+ if ((c = nextc(p)) == '=') {
+ return tASET;
+ }
+ pushback(p, c);
+ return tAREF;
+ }
+ pushback(p, c);
+ return '[';
+ }
+ else if (IS_BEG()) {
+ c = tLBRACK;
+ }
+ else if (IS_ARG() && space_seen) {
+ c = tLBRACK;
+ }
+ p->lstate = EXPR_BEG;
+ COND_PUSH(0);
+ CMDARG_PUSH(0);
+ return c;
+
+ case '{':
+ if (p->lpar_beg && p->lpar_beg == p->paren_nest) {
+ p->lstate = EXPR_BEG;
+ p->lpar_beg = 0;
+ p->paren_nest--;
+ COND_PUSH(0);
+ CMDARG_PUSH(0);
+ return tLAMBEG;
+ }
+ if (IS_ARG() || p->lstate == EXPR_END || p->lstate == EXPR_ENDFN)
+ c = '{'; /* block (primary) */
+ else if (p->lstate == EXPR_ENDARG)
+ c = tLBRACE_ARG; /* block (expr) */
+ else
+ c = tLBRACE; /* hash */
+ COND_PUSH(0);
+ CMDARG_PUSH(0);
+ p->lstate = EXPR_BEG;
+ return c;
+
+ case '\\':
+ c = nextc(p);
+ if (c == '\n') {
+ p->lineno+=nlines; nlines=1;
+ p->column = 0;
+ space_seen = 1;
+ goto retry; /* skip \\n */
+ }
+ pushback(p, c);
+ return '\\';
+
+ case '%':
+ if (IS_BEG()) {
+ int term;
+ int paren;
+
+ c = nextc(p);
+ quotation:
+ if (c < 0 || !ISALNUM(c)) {
+ term = c;
+ c = 'Q';
+ }
+ else {
+ term = nextc(p);
+ if (ISALNUM(term)) {
+ yyerror(NULL, p, "unknown type of %string");
+ return 0;
+ }
+ }
+ if (c < 0 || term < 0) {
+ yyerror(NULL, p, "unterminated quoted string meets end of file");
+ return 0;
+ }
+ paren = term;
+ if (term == '(') term = ')';
+ else if (term == '[') term = ']';
+ else if (term == '{') term = '}';
+ else if (term == '<') term = '>';
+ else paren = 0;
+
+ switch (c) {
+ case 'Q':
+ p->lex_strterm = new_strterm(p, str_dquote, term, paren);
+ return tSTRING_BEG;
+
+ case 'q':
+ p->lex_strterm = new_strterm(p, str_squote, term, paren);
+ return parse_string(p);
+
+ case 'W':
+ p->lex_strterm = new_strterm(p, str_dword, term, paren);
+ return tWORDS_BEG;
+
+ case 'w':
+ p->lex_strterm = new_strterm(p, str_sword, term, paren);
+ return tWORDS_BEG;
+
+ case 'x':
+ p->lex_strterm = new_strterm(p, str_xquote, term, paren);
+ return tXSTRING_BEG;
+
+ case 'r':
+ p->lex_strterm = new_strterm(p, str_regexp, term, paren);
+ return tREGEXP_BEG;
+
+ case 's':
+ p->lex_strterm = new_strterm(p, str_ssym, term, paren);
+ return tSYMBEG;
+
+ case 'I':
+ p->lex_strterm = new_strterm(p, str_dsymbols, term, paren);
+ return tSYMBOLS_BEG;
+
+ case 'i':
+ p->lex_strterm = new_strterm(p, str_ssymbols, term, paren);
+ return tSYMBOLS_BEG;
+
+ default:
+ yyerror(NULL, p, "unknown type of %string");
+ return 0;
+ }
+ }
+ if ((c = nextc(p)) == '=') {
+ pylval.id = intern_op(mod);
+ p->lstate = EXPR_BEG;
+ return tOP_ASGN;
+ }
+ if (IS_SPCARG(c)) {
+ goto quotation;
+ }
+ if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) {
+ p->lstate = EXPR_ARG;
+ }
+ else {
+ p->lstate = EXPR_BEG;
+ }
+ pushback(p, c);
+ return '%';
+
+ case '$':
+ p->lstate = EXPR_END;
+ token_column = newtok(p);
+ c = nextc(p);
+ if (c < 0) {
+ yyerror(NULL, p, "incomplete global variable syntax");
+ return 0;
+ }
+ switch (c) {
+ case '_': /* $_: last read line string */
+ c = nextc(p);
+ if (c >= 0 && identchar(c)) { /* if there is more after _ it is a variable */
+ tokadd(p, '$');
+ tokadd(p, c);
+ break;
+ }
+ pushback(p, c);
+ c = '_';
+ /* fall through */
+ case '~': /* $~: match-data */
+ case '*': /* $*: argv */
+ case '$': /* $$: pid */
+ case '?': /* $?: last status */
+ case '!': /* $!: error string */
+ case '@': /* $@: error position */
+ case '/': /* $/: input record separator */
+ case '\\': /* $\: output record separator */
+ case ';': /* $;: field separator */
+ case ',': /* $,: output field separator */
+ case '.': /* $.: last read line number */
+ case '=': /* $=: ignorecase */
+ case ':': /* $:: load path */
+ case '<': /* $<: reading filename */
+ case '>': /* $>: default output handle */
+ case '\"': /* $": already loaded files */
+ tokadd(p, '$');
+ tokadd(p, c);
+ tokfix(p);
+ pylval.id = intern(tok(p), toklen(p));
+ return tGVAR;
+
+ case '-':
+ tokadd(p, '$');
+ tokadd(p, c);
+ c = nextc(p);
+ pushback(p, c);
+ gvar:
+ tokfix(p);
+ pylval.id = intern(tok(p), toklen(p));
+ return tGVAR;
+
+ case '&': /* $&: last match */
+ case '`': /* $`: string before last match */
+ case '\'': /* $': string after last match */
+ case '+': /* $+: string matches last pattern */
+ if (last_state == EXPR_FNAME) {
+ tokadd(p, '$');
+ tokadd(p, c);
+ goto gvar;
+ }
+ pylval.nd = new_back_ref(p, c);
+ return tBACK_REF;
+
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ do {
+ tokadd(p, c);
+ c = nextc(p);
+ } while (c >= 0 && ISDIGIT(c));
+ pushback(p, c);
+ if (last_state == EXPR_FNAME) goto gvar;
+ tokfix(p);
+ {
+ mrb_int n;
+ if (!mrb_read_int(tok(p), NULL, NULL, &n)) {
+ yywarning(p, "capture group index too big; always nil");
+ return keyword_nil;
+ }
+ pylval.nd = new_nth_ref(p, (int)n);
+ }
+ return tNTH_REF;
+
+ default:
+ if (!identchar(c)) {
+ pushback(p, c);
+ return '$';
+ }
+ /* fall through */
+ case '0':
+ tokadd(p, '$');
+ }
+ break;
+
+ case '@':
+ c = nextc(p);
+ token_column = newtok(p);
+ tokadd(p, '@');
+ if (c == '@') {
+ tokadd(p, '@');
+ c = nextc(p);
+ }
+ if (c < 0) {
+ if (p->tidx == 1) {
+ yyerror(NULL, p, "incomplete instance variable syntax");
+ }
+ else {
+ yyerror(NULL, p, "incomplete class variable syntax");
+ }
+ return 0;
+ }
+ else if (ISDIGIT(c)) {
+ if (p->tidx == 1) {
+ yyerror_c(p, "wrong instance variable name: @", c);
+ }
+ else {
+ yyerror_c(p, "wrong class variable name: @@", c);
+ }
+ return 0;
+ }
+ if (!identchar(c)) {
+ pushback(p, c);
+ return '@';
+ }
+ break;
+
+ case '_':
+ token_column = newtok(p);
+ break;
+
+ default:
+ if (!identchar(c)) {
+ char buf[36];
+ const char s[] = "Invalid char in expression: 0x";
+ const char hexdigits[] = "0123456789ABCDEF";
+
+ strcpy(buf, s);
+ buf[sizeof(s)-1] = hexdigits[(c & 0xf0) >> 4];
+ buf[sizeof(s)] = hexdigits[(c & 0x0f)];
+ buf[sizeof(s)+1] = 0;
+ yyerror(NULL, p, buf);
+ goto retry;
+ }
+
+ token_column = newtok(p);
+ break;
+ }
+
+ do {
+ tokadd(p, c);
+ c = nextc(p);
+ if (c < 0) break;
+ } while (identchar(c));
+ if (token_column == 0 && toklen(p) == 7 && (c < 0 || c == '\n') &&
+ strncmp(tok(p), "__END__", toklen(p)) == 0)
+ return -1;
+
+ switch (tok(p)[0]) {
+ case '@': case '$':
+ pushback(p, c);
+ break;
+ default:
+ if ((c == '!' || c == '?') && !peek(p, '=')) {
+ tokadd(p, c);
+ }
+ else {
+ pushback(p, c);
+ }
+ }
+ tokfix(p);
+ {
+ int result = 0;
+
+ switch (tok(p)[0]) {
+ case '$':
+ p->lstate = EXPR_END;
+ result = tGVAR;
+ break;
+ case '@':
+ p->lstate = EXPR_END;
+ if (tok(p)[1] == '@')
+ result = tCVAR;
+ else
+ result = tIVAR;
+ break;
+
+ case '_':
+ if (toklen(p) == 2 && ISDIGIT(tok(p)[1]) && p->nvars) {
+ int n = tok(p)[1] - '0';
+ int nvar;
+
+ if (n > 0) {
+ nvar = node_to_int(p->nvars->car);
+ if (nvar != -2) { /* numbered parameters never appear on toplevel */
+ pylval.num = n;
+ p->lstate = EXPR_END;
+ return tNUMPARAM;
+ }
+ }
+ }
+ /* fall through */
+ default:
+ if (toklast(p) == '!' || toklast(p) == '?') {
+ result = tFID;
+ }
+ else {
+ if (p->lstate == EXPR_FNAME) {
+ if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') &&
+ (!peek(p, '=') || (peek_n(p, '>', 1)))) {
+ result = tIDENTIFIER;
+ tokadd(p, c);
+ tokfix(p);
+ }
+ else {
+ pushback(p, c);
+ }
+ if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') &&
+ (!peek(p, '=') || (peek_n(p, '>', 1)))) {
+ result = tIDENTIFIER;
+ tokadd(p, c);
+ tokfix(p);
+ }
+ else {
+ pushback(p, c);
+ }
+ }
+ if (result == 0 && ISUPPER(tok(p)[0])) {
+ result = tCONSTANT;
+ }
+ else {
+ result = tIDENTIFIER;
+ }
+ }
+
+ if (IS_LABEL_POSSIBLE()) {
+ if (IS_LABEL_SUFFIX(0)) {
+ p->lstate = EXPR_END;
+ tokfix(p);
+ pylval.id = intern(tok(p), toklen(p));
+ return tIDENTIFIER;
+ }
+ }
+ if (p->lstate != EXPR_DOT) {
+ const struct kwtable *kw;
+
+ /* See if it is a reserved word. */
+ kw = mrb_reserved_word(tok(p), toklen(p));
+ if (kw) {
+ enum mrb_lex_state_enum state = p->lstate;
+ pylval.num = p->lineno;
+ p->lstate = kw->state;
+ if (state == EXPR_FNAME) {
+ pylval.id = intern_cstr(kw->name);
+ return kw->id[0];
+ }
+ if (p->lstate == EXPR_BEG) {
+ p->cmd_start = TRUE;
+ }
+ if (kw->id[0] == keyword_do) {
+ if (p->lpar_beg && p->lpar_beg == p->paren_nest) {
+ p->lpar_beg = 0;
+ p->paren_nest--;
+ return keyword_do_LAMBDA;
+ }
+ if (COND_P()) return keyword_do_cond;
+ if (CMDARG_P() && state != EXPR_CMDARG)
+ return keyword_do_block;
+ if (state == EXPR_ENDARG || state == EXPR_BEG)
+ return keyword_do_block;
+ return keyword_do;
+ }
+ if (kw->id[0] == keyword_in) {
+ /* Set in_kwarg for pattern matching context */
+ p->in_kwarg++;
+ }
+ if (state == EXPR_BEG || state == EXPR_VALUE || state == EXPR_CLASS)
+ return kw->id[0];
+ else {
+ if (kw->id[0] != kw->id[1])
+ p->lstate = EXPR_BEG;
+ return kw->id[1];
+ }
+ }
+ }
+
+ if (IS_BEG() || p->lstate == EXPR_DOT || IS_ARG()) {
+ if (cmd_state) {
+ p->lstate = EXPR_CMDARG;
+ }
+ else {
+ p->lstate = EXPR_ARG;
+ }
+ }
+ else if (p->lstate == EXPR_FNAME) {
+ p->lstate = EXPR_ENDFN;
+ }
+ else {
+ p->lstate = EXPR_END;
+ }
+ }
+ {
+ mrb_sym ident = intern(tok(p), toklen(p));
+
+ pylval.id = ident;
+ if (last_state != EXPR_DOT && ISLOWER(tok(p)[0]) && local_var_p(p, ident)) {
+ p->lstate = EXPR_END;
+ }
+ }
+ return result;
+ }
+}
+
+static int
+yylex(void *lval, void *lp, parser_state *p)
+{
+ p->ylval = lval;
+ return parser_yylex(p);
+}
+
+static void
+parser_init_cxt(parser_state *p, mrb_ccontext *cxt)
+{
+ if (!cxt) return;
+ if (cxt->filename) mrb_parser_set_filename(p, cxt->filename);
+ if (cxt->lineno) p->lineno = cxt->lineno;
+ if (cxt->syms) {
+ int i;
+
+ p->locals = cons(0,0);
+ for (i=0; i<cxt->slen; i++) {
+ local_add_f(p, cxt->syms[i]);
+ }
+ }
+ p->capture_errors = cxt->capture_errors;
+ p->no_optimize = cxt->no_optimize;
+ p->no_ext_ops = cxt->no_ext_ops;
+ p->no_return_value = cxt->no_return_value;
+ p->upper = cxt->upper;
+ if (cxt->partial_hook) {
+ p->cxt = cxt;
+ }
+}
+
+static void
+parser_update_cxt(parser_state *p, mrb_ccontext *cxt)
+{
+ node *n, *n0;
+ int i = 0;
+
+ if (!cxt) return;
+ if (!p->tree) return;
+ if (!node_type_p(p->tree, NODE_SCOPE)) return;
+
+ /* Extract locals from variable-sized NODE_SCOPE */
+ struct mrb_ast_scope_node *scope = scope_node(p->tree);
+ n0 = n = scope->locals;
+ while (n) {
+ i++;
+ n = n->cdr;
+ }
+ cxt->syms = (mrb_sym*)mrbc_realloc(cxt->syms, i*sizeof(mrb_sym));
+ cxt->slen = i;
+ for (i=0, n=n0; n; i++,n=n->cdr) {
+ cxt->syms[i] = node_to_sym(n->car);
+ }
+}
+
+static void dump_node(mrb_state *mrb, node *tree, int offset);
+
+MRB_API void
+mrb_parser_parse(parser_state *p, mrb_ccontext *c)
+{
+ struct mrb_jmpbuf buf1;
+ struct mrb_jmpbuf *prev = p->mrb->jmp;
+ p->mrb->jmp = &buf1;
+
+ MRB_TRY(p->mrb->jmp) {
+ int n = 1;
+
+ p->cmd_start = TRUE;
+ p->in_def = p->in_single = 0;
+ p->nerr = p->nwarn = 0;
+ p->lex_strterm = NULL;
+ parser_init_cxt(p, c);
+
+ n = yyparse(p);
+ if (n != 0 || p->nerr > 0) {
+ p->tree = 0;
+ p->mrb->jmp = prev;
+ return;
+ }
+ parser_update_cxt(p, c);
+ if (c && c->dump_result) {
+ dump_node(p->mrb, p->tree, 0);
+ }
+ }
+ MRB_CATCH(p->mrb->jmp) {
+ p->nerr++;
+ if (p->mrb->exc == NULL) {
+ yyerror(NULL, p, "memory allocation error");
+ p->nerr++;
+ p->tree = 0;
+ }
+ }
+ MRB_END_EXC(p->jmp);
+ p->mrb->jmp = prev;
+}
+
+MRB_API parser_state*
+mrb_parser_new(mrb_state *mrb)
+{
+ mempool *pool;
+ parser_state *p;
+ static const parser_state parser_state_zero = { 0 };
+
+ pool = mempool_open();
+ if (!pool) return NULL;
+ p = (parser_state*)mempool_alloc(pool, sizeof(parser_state));
+ if (!p) return NULL;
+
+ *p = parser_state_zero;
+ p->mrb = mrb;
+ p->pool = pool;
+
+ p->s = p->send = NULL;
+#ifndef MRB_NO_STDIO
+ p->f = NULL;
+#endif
+
+ p->cmd_start = TRUE;
+ p->in_def = p->in_single = 0;
+
+ p->capture_errors = FALSE;
+ p->lineno = 1;
+ p->column = 0;
+#if defined(PARSER_TEST) || defined(PARSER_DEBUG)
+ yydebug = 1;
+#endif
+ p->tsiz = MRB_PARSER_TOKBUF_SIZE;
+ p->tokbuf = p->buf;
+
+ p->lex_strterm = NULL;
+
+ p->current_filename_index = -1;
+ p->filename_table = NULL;
+ p->filename_table_length = 0;
+
+ return p;
+}
+
+MRB_API void
+mrb_parser_free(parser_state *p) {
+ if (p->tokbuf != p->buf) {
+ mrbc_free(p->tokbuf);
+ }
+ mempool_close(p->pool);
+}
+
+MRB_API mrb_ccontext*
+mrb_ccontext_new(mrb_state *mrb)
+{
+ static const mrb_ccontext cc_zero = { 0 };
+ mrb_ccontext *cc = (mrb_ccontext*)mrbc_malloc(sizeof(mrb_ccontext));
+ *cc = cc_zero;
+ return cc;
+}
+
+MRB_API void
+mrb_ccontext_free(mrb_state *mrb, mrb_ccontext *cxt)
+{
+ mrbc_free(cxt->filename);
+ mrbc_free(cxt->syms);
+ mrbc_free(cxt);
+}
+
+MRB_API const char*
+mrb_ccontext_filename(mrb_state *mrb, mrb_ccontext *c, const char *s)
+{
+ if (s) {
+ size_t len = strlen(s);
+ char *p = (char*)mrbc_malloc(len + 1);
+
+ if (p == NULL) return NULL;
+ memcpy(p, s, len + 1);
+ if (c->filename) {
+ mrbc_free(c->filename);
+ }
+ c->filename = p;
+ }
+ return c->filename;
+}
+
+MRB_API void
+mrb_ccontext_partial_hook(mrb_ccontext *c, int (*func)(struct mrb_parser_state*), void *data)
+{
+ c->partial_hook = func;
+ c->partial_data = data;
+}
+
+MRB_API void
+mrb_ccontext_cleanup_local_variables(mrb_ccontext *c)
+{
+ if (c->syms) {
+ mrbc_free(c->syms);
+ c->syms = NULL;
+ c->slen = 0;
+ }
+ c->keep_lv = FALSE;
+}
+
+MRB_API void
+mrb_parser_set_filename(struct mrb_parser_state *p, const char *f)
+{
+ mrb_sym sym;
+ uint16_t i;
+ mrb_sym* new_table;
+
+ sym = mrb_intern_cstr(p->mrb, f);
+ p->filename_sym = sym;
+ p->lineno = (p->filename_table_length > 0)? 0 : 1;
+
+ for (i = 0; i < p->filename_table_length; i++) {
+ if (p->filename_table[i] == sym) {
+ p->current_filename_index = i;
+ return;
+ }
+ }
+
+ if (p->filename_table_length == UINT16_MAX) {
+ yyerror(NULL, p, "too many files to compile");
+ return;
+ }
+ p->current_filename_index = p->filename_table_length++;
+
+ new_table = (mrb_sym*)parser_palloc(p, sizeof(mrb_sym) * p->filename_table_length);
+ if (p->filename_table) {
+ memmove(new_table, p->filename_table, sizeof(mrb_sym) * p->current_filename_index);
+ }
+ p->filename_table = new_table;
+ p->filename_table[p->filename_table_length - 1] = sym;
+}
+
+MRB_API mrb_sym
+mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) {
+ if (idx >= p->filename_table_length) return 0;
+ else {
+ return p->filename_table[idx];
+ }
+}
+
+#ifndef MRB_NO_STDIO
+static struct mrb_parser_state *
+mrb_parse_file_continue(mrb_state *mrb, FILE *f, const void *prebuf, size_t prebufsize, mrb_ccontext *c)
+{
+ parser_state *p;
+
+ p = mrb_parser_new(mrb);
+ if (!p) return NULL;
+ if (prebuf) {
+ p->s = (const char*)prebuf;
+ p->send = (const char*)prebuf + prebufsize;
+ }
+ else {
+ p->s = p->send = NULL;
+ }
+ p->f = f;
+
+ mrb_parser_parse(p, c);
+ return p;
+}
+
+MRB_API parser_state*
+mrb_parse_file(mrb_state *mrb, FILE *f, mrb_ccontext *c)
+{
+ return mrb_parse_file_continue(mrb, f, NULL, 0, c);
+}
+#endif
+
+MRB_API parser_state*
+mrb_parse_nstring(mrb_state *mrb, const char *s, size_t len, mrb_ccontext *c)
+{
+ parser_state *p;
+
+ p = mrb_parser_new(mrb);
+ if (!p) return NULL;
+ p->s = s;
+ p->send = s + len;
+
+ mrb_parser_parse(p, c);
+ return p;
+}
+
+MRB_API parser_state*
+mrb_parse_string(mrb_state *mrb, const char *s, mrb_ccontext *c)
+{
+ return mrb_parse_nstring(mrb, s, strlen(s), c);
+}
+
+MRB_API mrb_value
+mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrb_ccontext *c)
+{
+ struct RClass *target = mrb->object_class;
+ struct RProc *proc;
+ mrb_value v;
+ mrb_int keep = 0;
+
+ if (!p) {
+ return mrb_undef_value();
+ }
+ if (!p->tree || p->nerr) {
+ if (c) c->parser_nerr = p->nerr;
+ if (p->capture_errors) {
+ char buf[256];
+
+ strcpy(buf, "line ");
+ dump_int(p->error_buffer[0].lineno, buf+5);
+ strcat(buf, ": ");
+ strncat(buf, p->error_buffer[0].message, sizeof(buf) - strlen(buf) - 1);
+ mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, strlen(buf)));
+ mrb_parser_free(p);
+ return mrb_undef_value();
+ }
+ else {
+ if (mrb->exc == NULL) {
+ mrb->exc = mrb_obj_ptr(mrb_exc_new_lit(mrb, E_SYNTAX_ERROR, "syntax error"));
+ }
+ mrb_parser_free(p);
+ return mrb_undef_value();
+ }
+ }
+ proc = mrb_generate_code(mrb, p);
+ mrb_parser_free(p);
+ if (proc == NULL) {
+ if (mrb->exc == NULL) {
+ mrb->exc = mrb_obj_ptr(mrb_exc_new_lit(mrb, E_SCRIPT_ERROR, "codegen error"));
+ }
+ return mrb_undef_value();
+ }
+ if (c) {
+ if (c->dump_result) mrb_codedump_all(mrb, proc);
+ if (c->no_exec) return mrb_obj_value(proc);
+ if (c->target_class) {
+ target = c->target_class;
+ }
+ if (c->keep_lv) {
+ keep = c->slen + 1;
+ }
+ else {
+ c->keep_lv = TRUE;
+ }
+ }
+ MRB_PROC_SET_TARGET_CLASS(proc, target);
+ if (mrb->c->ci) {
+ mrb_vm_ci_target_class_set(mrb->c->ci, target);
+ }
+ v = mrb_top_run(mrb, proc, mrb_top_self(mrb), keep);
+ if (mrb->exc) return mrb_nil_value();
+ return v;
+}
+
+#ifndef MRB_NO_STDIO
+MRB_API mrb_value
+mrb_load_file_cxt(mrb_state *mrb, FILE *f, mrb_ccontext *c)
+{
+ return mrb_load_exec(mrb, mrb_parse_file(mrb, f, c), c);
+}
+
+MRB_API mrb_value
+mrb_load_file(mrb_state *mrb, FILE *f)
+{
+ return mrb_load_file_cxt(mrb, f, NULL);
+}
+
+#define DETECT_SIZE 64
+
+/*
+ * In order to be recognized as a `.mrb` file, the following three points must be satisfied:
+ * - File starts with "RITE"
+ * - At least `sizeof(struct rite_binary_header)` bytes can be read
+ * - `NUL` is included in the first 64 bytes of the file
+ */
+MRB_API mrb_value
+mrb_load_detect_file_cxt(mrb_state *mrb, FILE *fp, mrb_ccontext *c)
+{
+ union {
+ char b[DETECT_SIZE];
+ struct rite_binary_header h;
+ } leading;
+ size_t bufsize;
+
+ if (mrb == NULL || fp == NULL) {
+ return mrb_nil_value();
+ }
+
+ bufsize = fread(leading.b, sizeof(char), sizeof(leading), fp);
+ if (bufsize < sizeof(leading.h) ||
+ memcmp(leading.h.binary_ident, RITE_BINARY_IDENT, sizeof(leading.h.binary_ident)) != 0 ||
+ memchr(leading.b, '\0', bufsize) == NULL) {
+ return mrb_load_exec(mrb, mrb_parse_file_continue(mrb, fp, leading.b, bufsize, c), c);
+ }
+ else {
+ mrb_int binsize = bin_to_uint32(leading.h.binary_size);
+ mrb_value bin_obj = mrb_str_new(mrb, NULL, binsize);
+ uint8_t *bin = (uint8_t*)RSTRING_PTR(bin_obj);
+ if ((size_t)binsize > bufsize) {
+ memcpy(bin, leading.b, bufsize);
+ if (fread(bin + bufsize, binsize - bufsize, 1, fp) == 0) {
+ binsize = bufsize;
+ /* The error is reported by mrb_load_irep_buf_cxt() */
+ }
+ }
+
+ mrb_value result = mrb_load_irep_buf_cxt(mrb, bin, binsize, c);
+ if (mrb_string_p(bin_obj)) mrb_str_resize(mrb, bin_obj, 0);
+ return result;
+ }
+}
+#endif
+
+MRB_API mrb_value
+mrb_load_nstring_cxt(mrb_state *mrb, const char *s, size_t len, mrb_ccontext *c)
+{
+ return mrb_load_exec(mrb, mrb_parse_nstring(mrb, s, len, c), c);
+}
+
+MRB_API mrb_value
+mrb_load_nstring(mrb_state *mrb, const char *s, size_t len)
+{
+ return mrb_load_nstring_cxt(mrb, s, len, NULL);
+}
+
+MRB_API mrb_value
+mrb_load_string_cxt(mrb_state *mrb, const char *s, mrb_ccontext *c)
+{
+ return mrb_load_nstring_cxt(mrb, s, strlen(s), c);
+}
+
+MRB_API mrb_value
+mrb_load_string(mrb_state *mrb, const char *s)
+{
+ return mrb_load_string_cxt(mrb, s, NULL);
+}
+
+#ifndef MRB_NO_STDIO
+
+static void
+dump_prefix(int offset, uint16_t lineno)
+{
+ printf("%05d ", lineno);
+ while (offset--) {
+ putc(' ', stdout);
+ putc(' ', stdout);
+ }
+}
+
+static void
+dump_recur(mrb_state *mrb, node *tree, int offset)
+{
+ while (tree) {
+ dump_node(mrb, tree->car, offset);
+ tree = tree->cdr;
+ }
+}
+
+static void
+dump_locals(mrb_state *mrb, node *tree, int offset, uint16_t lineno)
+{
+ if (!tree || (!tree->car && !tree->cdr)) return;
+
+ dump_prefix(offset, lineno);
+ printf("locals:\n");
+ dump_prefix(offset+1, lineno);
+ while (tree) {
+ if (tree->car) {
+ mrb_sym sym = node_to_sym(tree->car);
+ if (sym != 0) {
+ const char *name = mrb_sym_name(mrb, sym);
+ if (name && strlen(name) > 0 && name[0] != '!' && name[0] != '@' && name[0] != '$') {
+ printf(" %s", mrb_sym_dump(mrb, sym));
+ }
+ else {
+ printf(" (invalid symbol: %s)", name ? name : "(null)");
+ }
+ }
+ else {
+ printf(" (anonymous)");
+ }
+ }
+ tree = tree->cdr;
+ }
+ printf("\n");
+}
+
+static void
+dump_cpath(mrb_state *mrb, node *tree, int offset, uint16_t lineno)
+{
+ dump_prefix(offset, lineno);
+ printf("cpath: ");
+ if (!tree) {
+ printf("(null)\n");
+ }
+ else if (node_to_int(tree->car) == 0) {
+ printf("(null)\n");
+ }
+ else if (node_to_int(tree->car) == 1) {
+ printf("Object\n");
+ }
+ else {
+ printf("\n");
+ dump_node(mrb, tree->car, offset+1);
+ }
+ dump_prefix(offset, lineno);
+ printf("name: %s\n", mrb_sym_dump(mrb, node_to_sym(tree->cdr)));
+}
+
+/*
+ * This function restores the GC arena on return.
+ * For this reason, if a process that further generates an object is
+ * performed at the caller, the string pointer returned as the return
+ * value may become invalid.
+ */
+static const char*
+str_dump(mrb_state *mrb, const char *str, int len)
+{
+ int ai = mrb_gc_arena_save(mrb);
+ mrb_value s = mrb_str_new(mrb, str, (mrb_int)len);
+ s = mrb_str_dump(mrb, s);
+ mrb_gc_arena_restore(mrb, ai);
+ return RSTRING_PTR(s);
+}
+
+static void
+dump_str(mrb_state *mrb, node *n, int offset, uint16_t lineno)
+{
+ while (n) {
+ dump_prefix(offset, lineno);
+ int len = node_to_int(n->car->car);
+ if (len >= 0) {
+ printf("str: %s\n", str_dump(mrb, (char*)n->car->cdr, len));
+ }
+ else {
+ printf("interpolation:\n");
+ dump_node(mrb, n->car->cdr, offset+1);
+ }
+ n = n->cdr;
+ }
+}
+
+static void
+dump_args(mrb_state *mrb, struct mrb_ast_args *args, int offset, uint16_t lineno)
+{
+ if (args->mandatory_args) {
+ dump_prefix(offset, lineno);
+ printf("mandatory args:\n");
+ dump_recur(mrb, args->mandatory_args, offset+1);
+ }
+ if (args->optional_args) {
+ dump_prefix(offset, lineno);
+ printf("optional args:\n");
+ {
+ node *n = args->optional_args;
+ while (n) {
+ dump_prefix(offset+1, lineno);
+ printf("%s=\n", mrb_sym_name(mrb, node_to_sym(n->car->car)));
+ dump_node(mrb, n->car->cdr, offset+2);
+ n = n->cdr;
+ }
+ }
+ }
+ if (args->rest_arg) {
+ mrb_sym rest = args->rest_arg;
+
+ dump_prefix(offset, lineno);
+ if (rest == MRB_OPSYM(mul))
+ printf("rest=*\n");
+ else
+ printf("rest=*%s\n", mrb_sym_name(mrb, rest));
+ }
+ if (args->post_mandatory_args) {
+ dump_prefix(offset, lineno);
+ printf("post mandatory args:\n");
+ dump_recur(mrb, args->post_mandatory_args, offset+1);
+ }
+ if (args->keyword_args) {
+ dump_prefix(offset, lineno);
+ printf("keyword args:\n");
+ {
+ node *n = args->keyword_args;
+ while (n) {
+ dump_prefix(offset+1, lineno);
+ printf("%s:\n", mrb_sym_name(mrb, node_to_sym(n->car->car)));
+ dump_node(mrb, n->car->cdr, offset+2);
+ n = n->cdr;
+ }
+ }
+ }
+ if (args->kwrest_arg) {
+ mrb_sym rest = args->kwrest_arg;
+
+ dump_prefix(offset, lineno);
+ if (rest == MRB_OPSYM(pow))
+ printf("kwrest=**\n");
+ else
+ printf("kwrest=**%s\n", mrb_sym_name(mrb, rest));
+ }
+ if (args->block_arg) {
+ mrb_sym blk = args->block_arg;
+
+ dump_prefix(offset, lineno);
+ if (blk == MRB_OPSYM(and))
+ printf("blk=&\n");
+ else if (blk == MRB_SYM(nil))
+ printf("blk=&nil\n");
+ else
+ printf("blk=&%s\n", mrb_sym_name(mrb, blk));
+ }
+}
+
+static void
+dump_callargs(mrb_state *mrb, node *n, int offset, uint16_t lineno)
+{
+ if (!n) return;
+
+ struct mrb_ast_callargs *args = (struct mrb_ast_callargs*)n;
+ if (args->regular_args) {
+ dump_prefix(offset+1, lineno);
+ printf("args:\n");
+ dump_recur(mrb, args->regular_args, offset+2);
+ }
+ if (args->keyword_args) {
+ dump_prefix(offset+1, lineno);
+ printf("kw_args:\n");
+ node *kw = args->keyword_args;
+ while (kw) {
+ dump_prefix(offset+2, lineno);
+ printf("key:\n");
+ if (node_to_sym(kw->car->car) == MRB_OPSYM(pow)) {
+ dump_prefix(offset+3, lineno);
+ printf("**:\n");
+ }
+ else {
+ dump_node(mrb, kw->car->car, offset+3);
+ }
+ dump_prefix(offset+2, lineno);
+ printf("value:\n");
+ dump_node(mrb, kw->car->cdr, offset+3);
+ kw = kw->cdr;
+ }
+ }
+ if (args->block_arg) {
+ dump_prefix(offset+1, lineno);
+ printf("block:\n");
+ dump_node(mrb, args->block_arg, offset+2);
+ }
+}
+
+#endif
+
+void
+dump_node(mrb_state *mrb, node *tree, int offset)
+{
+#ifndef MRB_NO_STDIO
+ enum node_type nodetype;
+ uint16_t lineno = 0;
+
+ if (!tree) return;
+
+ /* Extract line number from variable-sized node header */
+ if (node_type(tree) != NODE_LAST) {
+ lineno = ((struct mrb_ast_var_header*)tree)->lineno;
+ }
+
+ dump_prefix(offset, lineno);
+
+ /* All nodes are now variable-sized nodes with headers */
+ nodetype = node_type(tree);
+
+ switch (nodetype) {
+ /* Variable-sized node cases */
+ case NODE_SCOPE:
+ printf("NODE_SCOPE:\n");
+ if (scope_node(tree)->locals) {
+ dump_locals(mrb, scope_node(tree)->locals, offset+1, lineno);
+ }
+ if (scope_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, scope_node(tree)->body, offset+2);
+ }
+ break;
+
+ case NODE_INT:
+ printf("NODE_INT: %d\n", int_node(tree)->value);
+ break;
+
+ case NODE_BIGINT:
+ printf("NODE_BIGINT: %s (base %d)\n", bigint_node(tree)->string, bigint_node(tree)->base);
+ break;
+
+ case NODE_FLOAT:
+ printf("NODE_FLOAT: %s\n", float_node(tree)->value);
+ break;
+
+ case NODE_STR:
+ printf("NODE_STR:\n");
+ dump_str(mrb, str_node(tree)->list, offset+1, lineno);
+ break;
+
+ case NODE_XSTR:
+ printf("NODE_XSTR:\n");
+ dump_str(mrb, xstr_node(tree)->list, offset+1, lineno);
+ break;
+
+ case NODE_SYM:
+ printf("NODE_SYM: %s\n", mrb_sym_dump(mrb, sym_node(tree)->symbol));
+ break;
+
+ case NODE_DSYM:
+ printf("NODE_DSYM:\n");
+ dump_str(mrb, str_node(tree)->list, offset+1, lineno);
+ break;
+
+ case NODE_LVAR:
+ printf("NODE_LVAR: %s\n", mrb_sym_dump(mrb, var_node(tree)->symbol));
+ break;
+
+ case NODE_GVAR:
+ printf("NODE_GVAR: %s\n", mrb_sym_dump(mrb, var_node(tree)->symbol));
+ break;
+
+ case NODE_IVAR:
+ printf("NODE_IVAR: %s\n", mrb_sym_dump(mrb, var_node(tree)->symbol));
+ break;
+
+ case NODE_CVAR:
+ printf("NODE_CVAR: %s\n", mrb_sym_dump(mrb, var_node(tree)->symbol));
+ break;
+
+ case NODE_NVAR:
+ printf("NODE_NVAR: %d\n", nvar_node(tree)->num);
+ break;
+
+ case NODE_CONST:
+ printf("NODE_CONST: %s\n", mrb_sym_dump(mrb, var_node(tree)->symbol));
+ break;
+
+ case NODE_CALL:
+ printf("NODE_CALL: %s\n", mrb_sym_dump(mrb, call_node(tree)->method_name));
+ if (call_node(tree)->receiver) {
+ dump_prefix(offset+1, lineno);
+ printf("receiver:\n");
+ dump_node(mrb, call_node(tree)->receiver, offset+2);
+ }
+ if (call_node(tree)->args) {
+ dump_callargs(mrb, call_node(tree)->args, offset, lineno);
+ }
+ break;
+
+ case NODE_ARRAY:
+ printf("NODE_ARRAY:\n");
+ if (array_node(tree)->elements) {
+ dump_recur(mrb, array_node(tree)->elements, offset+1);
+ }
+ break;
+
+ case NODE_TRUE:
+ printf("NODE_TRUE\n");
+ break;
+
+ case NODE_FALSE:
+ printf("NODE_FALSE\n");
+ break;
+
+ case NODE_NIL:
+ printf("NODE_NIL\n");
+ break;
+
+ case NODE_SELF:
+ printf("NODE_SELF\n");
+ break;
+
+ case NODE_IF:
+ printf("NODE_IF:\n");
+ if (if_node(tree)->condition) {
+ dump_prefix(offset+1, lineno);
+ printf("cond:\n");
+ dump_node(mrb, if_node(tree)->condition, offset+2);
+ }
+ if (if_node(tree)->then_body) {
+ dump_prefix(offset+1, lineno);
+ printf("then:\n");
+ dump_node(mrb, if_node(tree)->then_body, offset+2);
+ }
+ if (if_node(tree)->else_body) {
+ dump_prefix(offset+1, lineno);
+ printf("else:\n");
+ dump_node(mrb, if_node(tree)->else_body, offset+2);
+ }
+ break;
+
+ case NODE_DEF:
+ printf("NODE_DEF: %s\n", mrb_sym_dump(mrb, def_node(tree)->name));
+ if (def_node(tree)->args) {
+ dump_args(mrb, sdef_node(tree)->args, offset+1, lineno);
+ }
+ if (def_node(tree)->locals) {
+ dump_locals(mrb, def_node(tree)->locals, offset+1, lineno);
+ }
+ if (def_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, def_node(tree)->body, offset+2);
+ }
+ break;
+
+ case NODE_ASGN:
+ printf("NODE_ASGN:\n");
+ if (asgn_node(tree)->lhs) {
+ dump_prefix(offset+1, lineno);
+ printf("lhs:\n");
+ dump_node(mrb, asgn_node(tree)->lhs, offset+2);
+ }
+ if (asgn_node(tree)->rhs) {
+ dump_prefix(offset+1, lineno);
+ printf("rhs:\n");
+ dump_node(mrb, asgn_node(tree)->rhs, offset+2);
+ }
+ break;
+
+ case NODE_MASGN:
+ case NODE_MARG:
+ printf("%s:\n", node_type(tree) == NODE_MASGN ? "NODE_MASGN" : "NODE_MARG");
+ /* Handle pre-splat variables */
+ if (masgn_node(tree)->pre) {
+ dump_prefix(offset+1, lineno);
+ printf("pre:\n");
+ dump_recur(mrb, masgn_node(tree)->pre, offset+2);
+ }
+ /* Handle splat variable (can be -1 sentinel for anonymous splat) */
+ if (masgn_node(tree)->rest) {
+ if ((intptr_t)masgn_node(tree)->rest == -1) {
+ dump_prefix(offset+1, lineno);
+ printf("rest: *<anonymous>\n");
+ }
+ else {
+ dump_prefix(offset+1, lineno);
+ printf("rest:\n");
+ dump_node(mrb, masgn_node(tree)->rest, offset+2);
+ }
+ }
+ /* Handle post-splat variables */
+ if (masgn_node(tree)->post) {
+ dump_prefix(offset+1, lineno);
+ printf("post:\n");
+ dump_recur(mrb, masgn_node(tree)->post, offset+2);
+ }
+ if (masgn_node(tree)->rhs) {
+ dump_prefix(offset+1, lineno);
+ printf("rhs:\n");
+ dump_node(mrb, masgn_node(tree)->rhs, offset+2);
+ }
+ break;
+
+ case NODE_RETURN:
+ printf("NODE_RETURN:\n");
+ if (return_node(tree)->args) {
+ dump_node(mrb, return_node(tree)->args, offset);
+ }
+ break;
+
+ case NODE_BREAK:
+ printf("NODE_BREAK:\n");
+ if (break_node(tree)->value) {
+ dump_prefix(offset+1, lineno);
+ printf("value:\n");
+ dump_node(mrb, break_node(tree)->value, offset+2);
+ }
+ break;
+
+ case NODE_NEXT:
+ printf("NODE_NEXT:\n");
+ if (next_node(tree)->value) {
+ dump_prefix(offset+1, lineno);
+ printf("value:\n");
+ dump_node(mrb, next_node(tree)->value, offset+2);
+ }
+ break;
+
+ case NODE_NEGATE:
+ printf("NODE_NEGATE:\n");
+ if (negate_node(tree)->operand) {
+ dump_prefix(offset+1, lineno);
+ printf("operand:\n");
+ dump_node(mrb, negate_node(tree)->operand, offset+2);
+ }
+ break;
+
+ case NODE_STMTS:
+ printf("NODE_STMTS:\n");
+ if (stmts_node(tree)->stmts) {
+ dump_recur(mrb, stmts_node(tree)->stmts, offset+1);
+ }
+ break;
+
+ case NODE_BEGIN:
+ printf("NODE_BEGIN:\n");
+ if (begin_node(tree)->body) {
+ dump_node(mrb, begin_node(tree)->body, offset+1);
+ }
+ break;
+
+ case NODE_RESCUE:
+ printf("NODE_RESCUE:\n");
+ if (rescue_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, rescue_node(tree)->body, offset+2);
+ }
+ if (rescue_node(tree)->rescue_clauses) {
+ node *n2 = rescue_node(tree)->rescue_clauses;
+ dump_prefix(offset+1, lineno);
+ printf("rescue:\n");
+ while (n2) {
+ node *n3 = n2->car;
+ if (n3->car) {
+ dump_prefix(offset+2, lineno);
+ printf("handle classes:\n");
+ dump_recur(mrb, n3->car, offset+3);
+ }
+ if (n3->cdr->car) {
+ dump_prefix(offset+2, lineno);
+ printf("exc_var:\n");
+ dump_node(mrb, n3->cdr->car, offset+3);
+ }
+ if (n3->cdr->cdr->car) {
+ dump_prefix(offset+2, lineno);
+ printf("rescue body:\n");
+ dump_node(mrb, n3->cdr->cdr->car, offset+3);
+ }
+ n2 = n2->cdr;
+ }
+ }
+ if (rescue_node(tree)->else_clause) {
+ dump_prefix(offset+1, lineno);
+ printf("else:\n");
+ dump_node(mrb, rescue_node(tree)->else_clause, offset+2);
+ }
+ break;
+
+ case NODE_ENSURE:
+ printf("NODE_ENSURE:\n");
+ if (ensure_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, ensure_node(tree)->body, offset+2);
+ }
+ if (ensure_node(tree)->ensure_clause) {
+ dump_prefix(offset+1, lineno);
+ printf("ensure:\n");
+ dump_node(mrb, ensure_node(tree)->ensure_clause, offset+2);
+ }
+ break;
+
+ case NODE_LAMBDA:
+ printf("NODE_LAMBDA:\n");
+ goto block;
+
+ case NODE_BLOCK:
+ printf("NODE_BLOCK:\n");
+ block:
+ if (block_node(tree)->locals) {
+ dump_locals(mrb, block_node(tree)->locals, offset+1, lineno);
+ }
+ if (block_node(tree)->args) {
+ dump_args(mrb, block_node(tree)->args, offset+1, lineno);
+ }
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, block_node(tree)->body, offset+2);
+ break;
+
+ case NODE_AND:
+ printf("NODE_AND:\n");
+ dump_node(mrb, and_node(tree)->left, offset+1);
+ dump_node(mrb, and_node(tree)->right, offset+1);
+ break;
+
+ case NODE_OR:
+ printf("NODE_OR:\n");
+ dump_node(mrb, or_node(tree)->left, offset+1);
+ dump_node(mrb, or_node(tree)->right, offset+1);
+ break;
+
+ case NODE_CASE:
+ printf("NODE_CASE:\n");
+ if (case_node(tree)->value) {
+ dump_prefix(offset+1, lineno);
+ printf("value:\n");
+ dump_node(mrb, case_node(tree)->value, offset+2);
+ }
+ if (case_node(tree)->body) {
+ node *when_node = case_node(tree)->body;
+ while (when_node) {
+ dump_prefix(offset+1, lineno);
+ printf("when:\n");
+ node *when_clause = when_node->car;
+ if (when_clause && when_clause->car) {
+ dump_prefix(offset+2, lineno);
+ printf("cond:\n");
+ dump_recur(mrb, when_clause->car, offset+3);
+ }
+ if (when_clause && when_clause->cdr) {
+ dump_prefix(offset+2, lineno);
+ printf("body:\n");
+ dump_node(mrb, when_clause->cdr, offset+3);
+ }
+ when_node = when_node->cdr;
+ }
+ }
+ break;
+
+ case NODE_WHILE:
+ printf("NODE_WHILE:\n");
+ goto dump_loop_node;
+ case NODE_UNTIL:
+ printf("NODE_UNTIL:\n");
+ goto dump_loop_node;
+ case NODE_WHILE_MOD:
+ printf("NODE_WHILE_MOD:\n");
+ goto dump_loop_node;
+ case NODE_UNTIL_MOD:
+ printf("NODE_UNTIL_MOD:\n");
+
+ dump_loop_node:
+ dump_prefix(offset+1, lineno);
+ printf("cond:\n");
+ dump_node(mrb, while_node(tree)->condition, offset+2);
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, while_node(tree)->body, offset+2);
+ break;
+
+ case NODE_FOR:
+ printf("NODE_FOR:\n");
+ if (for_node(tree)->var) {
+ dump_prefix(offset+1, lineno);
+ printf("var:\n");
+ /* FOR_NODE_VAR structure:
+ * var_list->car: cons-list of pre-splat variables
+ * var_list->cdr->car: splat varnode (not a cons-list)
+ * var_list->cdr->cdr->car: cons-list of post-splat variables */
+ node *var_list = for_node(tree)->var;
+ if (var_list) {
+ dump_recur(mrb, var_list->car, offset+2);
+ if (var_list && var_list->cdr) {
+ /* Second element is a varnode, not a cons-list */
+ dump_prefix(offset+1, lineno);
+ printf("splat var:\n");
+ dump_node(mrb, var_list->cdr->car, offset+2);
+ if (var_list->cdr->cdr) {
+ /* Third element is a cons-list of post-splat variables */
+ dump_prefix(offset+1, lineno);
+ printf("post var:\n");
+ dump_recur(mrb, var_list->cdr->cdr->car, offset+2);
+ }
+ }
+ }
+ }
+ if (for_node(tree)->iterable) {
+ dump_prefix(offset+1, lineno);
+ printf("iterable:\n");
+ dump_node(mrb, for_node(tree)->iterable, offset+2);
+ }
+ if (for_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, for_node(tree)->body, offset+2);
+ }
+ break;
+
+ case NODE_DOT2:
+ printf("NODE_DOT2:\n");
+ {
+ if (dot2_node(tree)->left) {
+ dump_prefix(offset+1, lineno);
+ printf("left:\n");
+ dump_node(mrb, dot2_node(tree)->left, offset+2);
+ }
+ if (dot2_node(tree)->right) {
+ dump_prefix(offset+1, lineno);
+ printf("right:\n");
+ dump_node(mrb, dot2_node(tree)->right, offset+2);
+ }
+ }
+ break;
+
+ case NODE_DOT3:
+ printf("NODE_DOT3:\n");
+ {
+ if (dot3_node(tree)->left) {
+ dump_prefix(offset+1, lineno);
+ printf("left:\n");
+ dump_node(mrb, dot3_node(tree)->left, offset+2);
+ }
+ if (dot3_node(tree)->right) {
+ dump_prefix(offset+1, lineno);
+ printf("right:\n");
+ dump_node(mrb, dot3_node(tree)->right, offset+2);
+ }
+ }
+ break;
+
+ case NODE_COLON2:
+ printf("NODE_COLON2:\n");
+ if (colon2_node(tree)->base) {
+ dump_prefix(offset+1, lineno);
+ printf("base:\n");
+ dump_node(mrb, colon2_node(tree)->base, offset+2);
+ }
+ dump_prefix(offset+1, lineno);
+ printf("name: %s\n", mrb_sym_name(mrb, colon2_node(tree)->name));
+ break;
+
+ case NODE_COLON3:
+ printf("NODE_COLON3: ::%s\n", mrb_sym_name(mrb, colon3_node(tree)->name));
+ break;
+
+ case NODE_HASH:
+ printf("NODE_HASH:\n");
+ {
+ node *pairs = hash_node(tree)->pairs;
+ while (pairs) {
+ dump_prefix(offset+1, lineno);
+ printf("key:\n");
+ if (node_to_sym(pairs->car->car) == MRB_OPSYM(pow)) {
+ dump_prefix(offset+2, lineno);
+ printf("**\n");
+ }
+ else {
+ dump_node(mrb, pairs->car->car, offset+2);
+ }
+ dump_prefix(offset+1, lineno);
+ printf("value:\n");
+ dump_node(mrb, pairs->car->cdr, offset+2);
+ pairs = pairs->cdr;
+ }
+ }
+ break;
+
+ case NODE_SPLAT:
+ printf("NODE_SPLAT:\n");
+ dump_node(mrb, splat_node(tree)->value, offset+1);
+ break;
+
+ case NODE_OP_ASGN:
+ printf("NODE_OP_ASGN:\n");
+ dump_prefix(offset+1, lineno);
+ printf("lhs:\n");
+ dump_node(mrb, op_asgn_node(tree)->lhs, offset+2);
+ dump_prefix(offset+1, lineno);
+ printf("op='%s' (%d)\n", mrb_sym_name(mrb, op_asgn_node(tree)->op), (int)op_asgn_node(tree)->op);
+ dump_node(mrb, op_asgn_node(tree)->rhs, offset+1);
+ break;
+
+ case NODE_SUPER:
+ printf("NODE_SUPER:\n");
+ if (super_node(tree)->args) {
+ dump_callargs(mrb, super_node(tree)->args, offset, lineno);
+ }
+ break;
+
+ case NODE_ZSUPER:
+ printf("NODE_ZSUPER:\n");
+ if (super_node(tree)->args) {
+ dump_callargs(mrb, super_node(tree)->args, offset, lineno);
+ }
+ break;
+
+ case NODE_YIELD:
+ printf("NODE_YIELD:\n");
+ if (yield_node(tree)->args) {
+ dump_callargs(mrb, yield_node(tree)->args, offset, lineno);
+ }
+ break;
+
+ case NODE_REDO:
+ printf("NODE_REDO\n");
+ break;
+
+ case NODE_RETRY:
+ printf("NODE_RETRY\n");
+ break;
+
+ case NODE_BACK_REF:
+ printf("NODE_BACK_REF: $%c\n", node_to_int(tree));
+ break;
+
+ case NODE_NTH_REF:
+ printf("NODE_NTH_REF: $%d\n", node_to_int(tree));
+ break;
+
+ case NODE_BLOCK_ARG:
+ printf("NODE_BLOCK_ARG:\n");
+ dump_node(mrb, block_arg_node(tree)->value, offset+1);
+ break;
+
+ case NODE_REGX:
+ printf("NODE_REGX:\n");
+ if (regx_node(tree)->list) {
+ dump_str(mrb, regx_node(tree)->list, offset+1, lineno);
+ }
+ if (regx_node(tree)->flags) {
+ dump_prefix(offset+1, lineno);
+ printf("flags: %s\n", regx_node(tree)->flags);
+ }
+ if (regx_node(tree)->encoding) {
+ dump_prefix(offset+1, lineno);
+ printf("encoding: %s\n", regx_node(tree)->encoding);
+ }
+ break;
+
+ case NODE_WORDS:
+ printf("NODE_WORDS:\n");
+ if (words_node(tree)->args) {
+ node *list = words_node(tree)->args;
+ while (list && list->car) {
+ node *item = list->car;
+ if (item->car == 0 && item->cdr == 0) {
+ /* Skip separator (0 . 0) */
+ }
+ else if (item->car && item->cdr) {
+ /* String item: (len . str) */
+ dump_prefix(offset+1, lineno);
+ int len = node_to_int(item->car);
+ if (len >= 0 && len < 1000 && item->cdr) {
+ printf("word: \"%.*s\"\n", len, (char*)item->cdr);
+ }
+ }
+ list = list->cdr;
+ }
+ }
+ break;
+
+ case NODE_SYMBOLS:
+ printf("NODE_SYMBOLS:\n");
+ if (symbols_node(tree)->args) {
+ node *list = symbols_node(tree)->args;
+ while (list && list->car) {
+ node *item = list->car;
+ if (item->car == 0 && item->cdr == 0) {
+ /* Skip separator (0 . 0) */
+ } else if (item->car && item->cdr) {
+ /* String item: (len . str) */
+ dump_prefix(offset+1, lineno);
+ int len = node_to_int(item->car);
+ if (len >= 0 && len < 1000 && item->cdr) {
+ printf("symbol: \"%.*s\"\n", len, (char*)item->cdr);
+ }
+ }
+ list = list->cdr;
+ }
+ }
+ break;
+
+ case NODE_ALIAS:
+ printf("NODE_ALIAS %s %s:\n",
+ mrb_sym_dump(mrb, node_to_sym(tree->car)),
+ mrb_sym_dump(mrb, node_to_sym(tree->cdr)));
+ break;
+
+ case NODE_UNDEF:
+ printf("NODE_UNDEF");
+ {
+ node *t = tree;
+ while (t) {
+ printf(" %s", mrb_sym_dump(mrb, node_to_sym(t->car)));
+ t = t->cdr;
+ }
+ }
+ printf(":\n");
+ break;
+
+ case NODE_CLASS:
+ printf("NODE_CLASS:\n");
+ if (class_node(tree)->name) {
+ dump_cpath(mrb, module_node(tree)->name, offset+1, lineno);
+ }
+ if (class_node(tree)->superclass) {
+ dump_prefix(offset+1, lineno);
+ printf("super:\n");
+ dump_node(mrb, class_node(tree)->superclass, offset+2);
+ }
+ if (class_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, class_node(tree)->body->cdr, offset+2);
+ }
+ break;
+
+ case NODE_MODULE:
+ printf("NODE_MODULE:\n");
+ if (module_node(tree)->name) {
+ dump_cpath(mrb, module_node(tree)->name, offset+1, lineno);
+ }
+ if (module_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, module_node(tree)->body->cdr, offset+2);
+ }
+ break;
+
+ case NODE_SCLASS:
+ printf("NODE_SCLASS:\n");
+ if (sclass_node(tree)->obj) {
+ dump_prefix(offset+1, lineno);
+ printf("obj:\n");
+ dump_node(mrb, sclass_node(tree)->obj, offset+2);
+ }
+ if (sclass_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, sclass_node(tree)->body->cdr, offset+2);
+ }
+ break;
+
+ case NODE_SDEF:
+ printf("NODE_SDEF: %s\n", mrb_sym_dump(mrb, def_node(tree)->name));
+ if (sdef_node(tree)->obj) {
+ dump_prefix(offset+1, lineno);
+ printf("recv:\n");
+ dump_node(mrb, sdef_node(tree)->obj, offset+2);
+ }
+ if (sdef_node(tree)->args) {
+ dump_args(mrb, sdef_node(tree)->args, offset+1, lineno);
+ }
+ if (sdef_node(tree)->locals) {
+ dump_locals(mrb, sdef_node(tree)->locals, offset+1, lineno);
+ }
+ if (sdef_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, sdef_node(tree)->body, offset+2);
+ }
+ break;
+
+ case NODE_POSTEXE:
+ printf("NODE_POSTEXE:\n");
+ dump_node(mrb, tree, offset+1);
+ break;
+
+ case NODE_HEREDOC:
+ printf("NODE_HEREDOC:\n");
+ if (heredoc_node(tree)->info.term) {
+ dump_prefix(offset+1, lineno);
+ printf("terminator: \"%s\"\n", heredoc_node(tree)->info.term);
+ }
+ if (heredoc_node(tree)->info.doc) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_str(mrb, heredoc_node(tree)->info.doc, offset+2, lineno);
+ }
+ if (heredoc_node(tree)->info.allow_indent) {
+ dump_prefix(offset+1, lineno);
+ printf("allow_indent: true\n");
+ }
+ if (heredoc_node(tree)->info.remove_indent) {
+ dump_prefix(offset+1, lineno);
+ printf("remove_indent: true\n");
+ }
+ break;
+
+ case NODE_CASE_MATCH:
+ printf("NODE_CASE_MATCH:\n");
+ if (case_match_node(tree)->value) {
+ dump_prefix(offset+1, lineno);
+ printf("value:\n");
+ dump_node(mrb, case_match_node(tree)->value, offset+2);
+ }
+ if (case_match_node(tree)->in_clauses) {
+ node *in_clause = case_match_node(tree)->in_clauses;
+ while (in_clause) {
+ dump_node(mrb, in_clause->car, offset+1);
+ in_clause = in_clause->cdr;
+ }
+ }
+ break;
+
+ case NODE_IN:
+ printf("NODE_IN:\n");
+ if (in_node(tree)->pattern) {
+ dump_prefix(offset+1, lineno);
+ printf("pattern:\n");
+ dump_node(mrb, in_node(tree)->pattern, offset+2);
+ }
+ if (in_node(tree)->guard) {
+ dump_prefix(offset+1, lineno);
+ printf("guard (%s):\n", in_node(tree)->guard_is_unless ? "unless" : "if");
+ dump_node(mrb, in_node(tree)->guard, offset+2);
+ }
+ if (in_node(tree)->body) {
+ dump_prefix(offset+1, lineno);
+ printf("body:\n");
+ dump_node(mrb, in_node(tree)->body, offset+2);
+ }
+ break;
+
+ case NODE_PAT_VALUE:
+ printf("NODE_PAT_VALUE:\n");
+ if (pat_value_node(tree)->value) {
+ dump_node(mrb, pat_value_node(tree)->value, offset+1);
+ }
+ break;
+
+ case NODE_PAT_VAR:
+ if (pat_var_node(tree)->name) {
+ printf("NODE_PAT_VAR: %s\n", mrb_sym_dump(mrb, pat_var_node(tree)->name));
+ }
+ else {
+ printf("NODE_PAT_VAR: _ (wildcard)\n");
+ }
+ break;
+
+ case NODE_PAT_PIN:
+ printf("NODE_PAT_PIN: ^%s\n", mrb_sym_dump(mrb, pat_pin_node(tree)->name));
+ break;
+
+ case NODE_PAT_AS:
+ printf("NODE_PAT_AS: => %s\n", mrb_sym_dump(mrb, pat_as_node(tree)->name));
+ if (pat_as_node(tree)->pattern) {
+ dump_prefix(offset+1, lineno);
+ printf("pattern:\n");
+ dump_node(mrb, pat_as_node(tree)->pattern, offset+2);
+ }
+ break;
+
+ case NODE_PAT_ALT:
+ printf("NODE_PAT_ALT:\n");
+ if (pat_alt_node(tree)->left) {
+ dump_prefix(offset+1, lineno);
+ printf("left:\n");
+ dump_node(mrb, pat_alt_node(tree)->left, offset+2);
+ }
+ if (pat_alt_node(tree)->right) {
+ dump_prefix(offset+1, lineno);
+ printf("right:\n");
+ dump_node(mrb, pat_alt_node(tree)->right, offset+2);
+ }
+ break;
+
+ case NODE_PAT_ARRAY:
+ printf("NODE_PAT_ARRAY:\n");
+ if (pat_array_node(tree)->pre) {
+ dump_prefix(offset+1, lineno);
+ printf("pre:\n");
+ dump_recur(mrb, pat_array_node(tree)->pre, offset+2);
+ }
+ if (pat_array_node(tree)->rest) {
+ dump_prefix(offset+1, lineno);
+ if (pat_array_node(tree)->rest == (node*)-1) {
+ printf("rest: * (anonymous)\n");
+ }
+ else {
+ printf("rest:\n");
+ dump_node(mrb, pat_array_node(tree)->rest, offset+2);
+ }
+ }
+ if (pat_array_node(tree)->post) {
+ dump_prefix(offset+1, lineno);
+ printf("post:\n");
+ dump_recur(mrb, pat_array_node(tree)->post, offset+2);
+ }
+ break;
+
+ case NODE_PAT_HASH:
+ printf("NODE_PAT_HASH:\n");
+ if (pat_hash_node(tree)->pairs) {
+ dump_prefix(offset+1, lineno);
+ printf("pairs:\n");
+ dump_recur(mrb, pat_hash_node(tree)->pairs, offset+2);
+ }
+ if (pat_hash_node(tree)->rest) {
+ dump_prefix(offset+1, lineno);
+ if (pat_hash_node(tree)->rest == (node*)-1) {
+ printf("rest: **nil\n");
+ }
+ else {
+ printf("rest:\n");
+ dump_node(mrb, pat_hash_node(tree)->rest, offset+2);
+ }
+ }
+ break;
+
+ case NODE_MATCH_PAT:
+ printf("NODE_MATCH_PAT%s:\n", match_pat_node(tree)->raise_on_fail ? " (=>)" : " (in)");
+ dump_prefix(offset+1, lineno);
+ printf("value:\n");
+ dump_node(mrb, match_pat_node(tree)->value, offset+2);
+ dump_prefix(offset+1, lineno);
+ printf("pattern:\n");
+ dump_node(mrb, match_pat_node(tree)->pattern, offset+2);
+ break;
+
+ default:
+ /* Fallback: unknown node type - skip like codegen.c does */
+ printf("unknown node type %d (0x%x)\n", nodetype, (unsigned)nodetype);
+ break;
+ }
+#endif
+}
+
+void
+mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
+{
+ dump_node(mrb, tree, offset);
+}
+
+typedef mrb_bool mrb_parser_foreach_top_variable_func(mrb_state *mrb, mrb_sym sym, void *user);
+void mrb_parser_foreach_top_variable(mrb_state *mrb, struct mrb_parser_state *p, mrb_parser_foreach_top_variable_func *func, void *user);
+
+void
+mrb_parser_foreach_top_variable(mrb_state *mrb, struct mrb_parser_state *p, mrb_parser_foreach_top_variable_func *func, void *user)
+{
+ const mrb_ast_node *n = p->tree;
+ if (node_type_p((node*)n, NODE_SCOPE)) {
+ /* Extract locals from variable-sized NODE_SCOPE */
+ struct mrb_ast_scope_node *scope = scope_node(n);
+ n = scope->locals;
+ for (; n; n = n->cdr) {
+ mrb_sym sym = node_to_sym(n->car);
+ if (sym != 0) {
+ if (!func(mrb, sym, user)) break;
+ }
+ }
+ }
+}