diff options
| author | Nobuhiro Iwamatsu <iwamatsu@debian.org> | 2026-06-30 16:07:15 +0900 |
|---|---|---|
| committer | git-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com> | 2026-06-30 16:34:09 +0000 |
| commit | 7045fd64b743827a6c67eac54a81196f2cb9a3be (patch) | |
| tree | f6e0de36aeee5f8cef19aa814027a917549abcff /mrbgems/mruby-compiler/core | |
| parent | b9bf429f92ff037e31812f9989fdb51add8c775a (diff) | |
4.0.0-1 (patches unapplied)HEADimport/4.0.0-1ubuntu/stonking-proposedubuntu/stonking-develubuntu/develdebian/sid
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.c | 6835 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/node.h | 723 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/parse.y | 3651 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/y.tab.c | 16165 |
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; + } + } + } +} |
