From da7be2e890c67abdc0f766a06fffd33aa7e06a6e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 20 Mar 2026 12:51:18 -0700 Subject: [PATCH 01/21] ZJIT: Optimize codegen (#16426) * eliminate redundant jumps * update merge tests * add some test coverage * push insns as usual * wipwipwip * fix reg imm imm * update tests * oops * collapse some branches * refactor x86 split pass * remove unused assert * do not hardcode reg numbers * fix rust errors --- zjit/src/backend/lir.rs | 14 +- zjit/src/backend/x86_64/mod.rs | 541 ++++++++++++++++++++++++++++----- 2 files changed, 473 insertions(+), 82 deletions(-) diff --git a/zjit/src/backend/lir.rs b/zjit/src/backend/lir.rs index 062c8243642f4b..4640bac15c6b02 100644 --- a/zjit/src/backend/lir.rs +++ b/zjit/src/backend/lir.rs @@ -1810,7 +1810,7 @@ impl Assembler let block_ids = self.block_order(); let num_blocks = block_ids.len(); - for block_id in block_ids { + for (i, block_id) in block_ids.iter().enumerate() { let block = &self.basic_blocks[block_id.0]; // Entry blocks shouldn't ever be preceded by something that can // stomp on this block. @@ -1823,6 +1823,18 @@ impl Assembler self.expand_branch_insn(insn, &mut insns); } + // Eliminate redundant jumps: if the last instruction is an + // unconditional jump to the next block in the linear order, + // remove it and let execution fall through. + if let Some(next_block_id) = block_ids.get(i + 1) { + let next_label = self.block_label(*next_block_id); + if let Some(Insn::Jmp(Target::Label(label))) = insns.last() { + if *label == next_label { + insns.pop(); + } + } + } + // Make sure we don't stomp on the next function if block_id.0 == num_blocks - 1 { insns.push(Insn::PadPatchPoint); diff --git a/zjit/src/backend/x86_64/mod.rs b/zjit/src/backend/x86_64/mod.rs index 476670ee4922ff..661093e78dc748 100644 --- a/zjit/src/backend/x86_64/mod.rs +++ b/zjit/src/backend/x86_64/mod.rs @@ -183,40 +183,12 @@ impl Assembler { // being used. It is okay not to use their output here. #[allow(unused_must_use)] match &mut insn { - Insn::Add { left, right, out } | - Insn::Sub { left, right, out } | - Insn::Mul { left, right, out } | - Insn::And { left, right, out } | - Insn::Or { left, right, out } | - Insn::Xor { left, right, out } => { - match (*left, *right) { - (Opnd::Mem(_), Opnd::Mem(_)) => { - *left = asm.load(*left); - *right = asm.load(*right); - }, - (Opnd::Mem(_), Opnd::UImm(_) | Opnd::Imm(_)) => { - *left = asm.load(*left); - }, - // Instruction output whose live range spans beyond this instruction - (Opnd::VReg { idx: _, .. }, _) => { - *left = asm.load(*left); - }, - // We have to load memory operands to avoid corrupting them - (Opnd::Mem(_), _) => { - *left = asm.load(*left); - }, - // We have to load register operands to avoid corrupting them - (Opnd::Reg(_), _) => { - if *left != *out { - *left = asm.load(*left); - } - }, - // The first operand can't be an immediate value - (Opnd::UImm(_), _) => { - *left = asm.load(*left); - } - _ => {} - } + Insn::Add { .. } | + Insn::Sub { .. } | + Insn::Mul { .. } | + Insn::And { .. } | + Insn::Or { .. } | + Insn::Xor { .. } => { asm.push_insn(insn); }, Insn::Cmp { left, right } => { @@ -427,6 +399,13 @@ impl Assembler { } } + fn assert_out_is_phys_reg_or_stack_mem(out: Opnd) { + assert!( + matches!(out, Opnd::Reg(_) | Opnd::Mem(Mem { base: MemBase::Stack { .. }, .. })), + "x86_scratch_split expects out to be a physical register or stack memory, got {out:?}" + ); + } + /// If both opnd and other are Opnd::Mem, split opnd with scratch_opnd. fn split_if_both_memory(asm: &mut Assembler, opnd: Opnd, other: Opnd, scratch_opnd: Opnd) -> Opnd { if let (Opnd::Mem(_), Opnd::Mem(_)) = (opnd, other) { @@ -481,17 +460,59 @@ impl Assembler { Insn::And { left, right, out } | Insn::Or { left, right, out } | Insn::Xor { left, right, out } => { + assert_out_is_phys_reg_or_stack_mem(*out); + + // Sequential pipeline to lower binops into x86 two-operand form. + // Uses SCRATCH0 for left, SCRATCH1 for right to avoid conflicts. + + // Phase 1: Protect right if it occupies the same location as out, + // since we'll overwrite out when moving left into it. + // Compare before lowering (Stack membases change during lowering). + let right_eq_out = out == right; + *out = lower_stack_membase(*out, &stack_state); + if right_eq_out { + asm.mov(SCRATCH1_OPND, *out); + *right = SCRATCH1_OPND; + } + + // Phase 2: Lower stack memory bases *left = split_stack_membase(asm, *left, SCRATCH0_OPND, &stack_state); - *left = split_if_both_memory(asm, *left, *right, SCRATCH0_OPND); - *right = split_stack_membase(asm, *right, SCRATCH1_OPND, &stack_state); + if !right_eq_out { + *right = split_stack_membase(asm, *right, SCRATCH1_OPND, &stack_state); + } + + // Phase 3: If right is a Mem whose base register equals the out + // register, materialize it before we clobber out. + if let (Opnd::Reg(out_reg), Opnd::Mem(Mem { base: MemBase::Reg(base_reg_no), .. })) = (*out, *right) { + if out_reg.reg_no == base_reg_no { + asm.mov(SCRATCH1_OPND, *right); + *right = SCRATCH1_OPND; + } + } + + // Phase 4: x86 can't encode two memory operands. + if let (Opnd::Mem(_), Opnd::Mem(_)) = (*out, *right) { + asm.mov(SCRATCH1_OPND, *right); + *right = SCRATCH1_OPND; + } + + // Phase 5: Move left into out (x86 two-operand form: OP clobbers dst). + // For Mem out, split large left immediates first (mov [mem], imm64 is invalid). + if let Opnd::Mem(_) = *out { + *left = split_64bit_immediate(asm, *left, SCRATCH0_OPND); + } + asm_mov(asm, *out, *left, SCRATCH0_OPND); + *left = *out; + + // Phase 6: Split large right immediates (>32-bit) into a register. *right = split_64bit_immediate(asm, *right, SCRATCH1_OPND); - *out = lower_stack_membase(*out, &stack_state); - let (out, left) = (*out, *left); + // Phase 7: Emit the instruction. asm.push_insn(insn); - asm_mov(asm, out, left, SCRATCH0_OPND); } Insn::Mul { left, right, out } => { + assert_out_is_phys_reg_or_stack_mem(*out); + *left = split_stack_membase(asm, *left, SCRATCH0_OPND, &stack_state); *left = split_if_both_memory(asm, *left, *right, SCRATCH0_OPND); *right = split_stack_membase(asm, *right, SCRATCH1_OPND, &stack_state); @@ -1243,6 +1264,119 @@ mod tests { (asm, CodeBlock::new_dummy()) } + fn stack_mem(stack_idx: usize) -> Opnd { + Opnd::Mem(Mem { + base: MemBase::Stack { stack_idx, num_bits: 64 }, + disp: 0, + num_bits: 64, + }) + } + + fn stack_indirect_mem(stack_idx: usize) -> Opnd { + Opnd::Mem(Mem { + base: MemBase::StackIndirect { stack_idx }, + disp: 0, + num_bits: 64, + }) + } + + #[derive(Clone, Copy, Debug)] + enum BinOpKind { + Add, + Sub, + And, + Or, + Xor, + } + + fn split_binop(kind: BinOpKind, left: Opnd, right: Opnd, out: Opnd) -> Assembler { + let (mut asm, _) = setup_asm(); + match kind { + BinOpKind::Add => asm.push_insn(Insn::Add { left, right, out }), + BinOpKind::Sub => asm.push_insn(Insn::Sub { left, right, out }), + BinOpKind::And => asm.push_insn(Insn::And { left, right, out }), + BinOpKind::Or => asm.push_insn(Insn::Or { left, right, out }), + BinOpKind::Xor => asm.push_insn(Insn::Xor { left, right, out }), + } + asm.x86_scratch_split() + } + + fn binop_mnemonic(kind: BinOpKind) -> &'static str { + match kind { + BinOpKind::Add => "add", + BinOpKind::Sub => "sub", + BinOpKind::And => "and", + BinOpKind::Or => "or", + BinOpKind::Xor => "xor", + } + } + + fn split_binop_disasm_lines(kind: BinOpKind, left: Opnd, right: Opnd, out: Opnd) -> Vec { + let mut asm = split_binop(kind, left, right, out); + let mut cb = CodeBlock::new_dummy(); + for name in &asm.label_names { + cb.new_label(name.to_string()); + } + assert!(asm.x86_emit(&mut cb).is_some(), "{kind:?}: x86_emit failed"); + + cb.disasm() + .lines() + .map(str::trim) + .filter(|line| !line.is_empty()) + .map(|line| { + line.split_once(": ") + .map(|(_, rest)| rest.to_string()) + .unwrap_or_else(|| line.to_string()) + }) + .collect() + } + + fn assert_split_binop_case(kind: BinOpKind, left: Opnd, right: Opnd, out: Opnd, case: &str) { + fn reg_names(reg: Reg) -> (&'static str, &'static str) { + const RAX_NO: u8 = RAX_REG.reg_no; + const RDI_NO: u8 = RDI_REG.reg_no; + const R13_NO: u8 = R13_REG.reg_no; + match reg.reg_no { + RAX_NO => ("rax", "eax"), + RDI_NO => ("rdi", "edi"), + R13_NO => ("r13", "r13d"), + _ => panic!("unexpected register in test helper: {reg:?}"), + } + } + + let lines = split_binop_disasm_lines(kind, left, right, out); + let mnemonic = binop_mnemonic(kind); + let matching: Vec<(usize, &String)> = lines.iter() + .enumerate() + .filter(|(_, line)| line.starts_with(&format!("{mnemonic} "))) + .collect(); + + assert_eq!(matching.len(), 1, "{kind:?} {case}: expected exactly one `{mnemonic}` in disasm, got {lines:?}"); + assert!( + !matching[0].1.contains("], qword ptr ["), + "{kind:?} {case}: emitted mem/mem `{mnemonic}` in disasm {lines:?}" + ); + + if let (Opnd::Reg(out_reg), Opnd::Imm(_) | Opnd::UImm(_)) = (out, left) { + let (out64, out32) = reg_names(out_reg); + let prelude = &lines[..matching[0].0]; + assert!( + prelude.iter().any(|line| + line.starts_with(&format!("mov {out64}, ")) || + line.starts_with(&format!("mov {out32}, ")) || + line.starts_with(&format!("movabs {out64}, ")) + ), + "{kind:?} {case}: expected left immediate to be materialized into output register before `{mnemonic}`, got {lines:?}" + ); + } + + if matches!(right, Opnd::Imm(value) if imm_num_bits(value) > 32) + || matches!(right, Opnd::UImm(value) if imm_num_bits(value as i64) > 32) + { + assert!(lines.iter().any(|line| line.starts_with("movabs ")), "{kind:?} {case}: expected movabs materialization for 64-bit immediate, got {lines:?}"); + } + } + #[test] fn test_lir_string() { use crate::hir::SideExitReason; @@ -1587,12 +1721,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_disasm_snapshot!(cb.disasm(), @" - 0x0: mov rdi, r13 - 0x3: add rdi, 0x40 - 0x7: mov r13, rdi - "); - assert_snapshot!(cb.hexdump(), @"4c89ef4883c7404989fd"); + assert_disasm_snapshot!(cb.disasm(), @" 0x0: add r13, 0x40"); + assert_snapshot!(cb.hexdump(), @"4983c540"); } #[test] @@ -1614,12 +1744,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_disasm_snapshot!(cb.disasm(), @" - 0x0: mov rdi, r13 - 0x3: sub rdi, 0x40 - 0x7: mov r13, rdi - "); - assert_snapshot!(cb.hexdump(), @"4c89ef4883ef404989fd"); + assert_disasm_snapshot!(cb.disasm(), @" 0x0: sub r13, 0x40"); + assert_snapshot!(cb.hexdump(), @"4983ed40"); } #[test] @@ -1641,12 +1767,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_disasm_snapshot!(cb.disasm(), @" - 0x0: mov rdi, r13 - 0x3: and rdi, 0x40 - 0x7: mov r13, rdi - "); - assert_snapshot!(cb.hexdump(), @"4c89ef4883e7404989fd"); + assert_disasm_snapshot!(cb.disasm(), @" 0x0: and r13, 0x40"); + assert_snapshot!(cb.hexdump(), @"4983e540"); } #[test] @@ -1657,12 +1779,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_disasm_snapshot!(cb.disasm(), @" - 0x0: mov rdi, r13 - 0x3: or rdi, 0x40 - 0x7: mov r13, rdi - "); - assert_snapshot!(cb.hexdump(), @"4c89ef4883cf404989fd"); + assert_disasm_snapshot!(cb.disasm(), @" 0x0: or r13, 0x40"); + assert_snapshot!(cb.hexdump(), @"4983cd40"); } #[test] @@ -1673,12 +1791,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_disasm_snapshot!(cb.disasm(), @" - 0x0: mov rdi, r13 - 0x3: xor rdi, 0x40 - 0x7: mov r13, rdi - "); - assert_snapshot!(cb.hexdump(), @"4c89ef4883f7404989fd"); + assert_disasm_snapshot!(cb.disasm(), @" 0x0: xor r13, 0x40"); + assert_snapshot!(cb.hexdump(), @"4983f540"); } #[test] @@ -1834,12 +1948,11 @@ mod tests { 0x20: pop rdx 0x21: pop rsi 0x22: pop rdi - 0x23: mov rdi, rdi - 0x26: add rdi, rsi - 0x29: mov rdi, rdx - 0x2c: add rdi, rcx + 0x23: add rdi, rsi + 0x26: mov rdi, rdx + 0x29: add rdi, rcx "); - assert_snapshot!(cb.hexdump(), @"bf01000000be02000000ba03000000b90400000057565251b800000000ffd0595a5e5f4889ff4801f74889d74801cf"); + assert_snapshot!(cb.hexdump(), @"bf01000000be02000000ba03000000b90400000057565251b800000000ffd0595a5e5f4801f74889d74801cf"); } #[test] @@ -1878,14 +1991,13 @@ mod tests { 0x2c: pop rdx 0x2d: pop rsi 0x2e: pop rdi - 0x2f: mov rdi, rdi - 0x32: add rdi, rsi - 0x35: mov rdi, rdx - 0x38: add rdi, rcx - 0x3b: mov rdi, rdx - 0x3e: add rdi, r8 + 0x2f: add rdi, rsi + 0x32: mov rdi, rdx + 0x35: add rdi, rcx + 0x38: mov rdi, rdx + 0x3b: add rdi, r8 "); - assert_snapshot!(cb.hexdump(), @"bf01000000be02000000ba03000000b90400000041b80500000057565251415057b800000000ffd05f4158595a5e5f4889ff4801f74889d74801cf4889d74c01c7"); + assert_snapshot!(cb.hexdump(), @"bf01000000be02000000ba03000000b90400000041b80500000057565251415057b800000000ffd05f4158595a5e5f4801f74889d74801cf4889d74c01c7"); } #[test] @@ -2078,4 +2190,271 @@ mod tests { "); assert_snapshot!(cb.hexdump(), @"4c8d5df84c895df8"); } + + #[test] + fn test_add_split_direct_mem() { + // RAX is safe to be clobbered because it's an output + // c_ret <- add stack[0], stack[1] + let lines = split_binop_disasm_lines(BinOpKind::Add, stack_mem(0), stack_mem(1), C_RET_OPND); + + // load scratch0, [stack[0]] + // add scratch0, [stack[1]] + // mov c_ret, scratch0 + assert_snapshot!(lines.join("\n"), @" + mov rax, qword ptr [rbp - 8] + add rax, qword ptr [rbp - 0x10] + "); + } + + #[test] + fn test_add_split_stack_indirect_left_uses_scratch0_for_base_and_result() { + // stack[1] <- add stack[mem[0]], cfp + let lines = split_binop_disasm_lines(BinOpKind::Add, stack_indirect_mem(0), CFP, stack_mem(1)); + + // load scratch0, [stack[left_base]] + // load scratch0, [scratch0] + // seed [stack[out]] from scratch0, then add right in place + assert_snapshot!(lines.join("\n"), @" + mov r11, qword ptr [rbp - 8] + mov r11, qword ptr [r11] + mov qword ptr [rbp - 0x10], r11 + add qword ptr [rbp - 0x10], r13 + "); + } + + #[test] + fn test_add_split_stack_indirect_right_uses_separate_base_scratch() { + // mem[1] <- add cfp, mem[stack[0]] + let lines = split_binop_disasm_lines(BinOpKind::Add, CFP, stack_indirect_mem(0), stack_mem(1)); + + // load scratch1, [stack[right_base]] + // load scratch1, [scratch1] + // seed [stack[out]] from left, then add scratch1 in place + assert_snapshot!(lines.join("\n"), @" + mov r10, qword ptr [rbp - 8] + mov r10, qword ptr [r10] + mov qword ptr [rbp - 0x10], r13 + add qword ptr [rbp - 0x10], r10 + "); + } + + #[test] + fn test_add_split_two_stack_indirect_inputs_need_two_scratch_regs() { + // stack[2] <- add [stack[0]], [stack[1]] + let lines = split_binop_disasm_lines(BinOpKind::Add, + stack_indirect_mem(0), stack_indirect_mem(1), stack_mem(2)); + + // load scratch0, [stack[left_base]] + // load scratch0, [scratch0] + // load scratch1, [stack[right_base]] + // load scratch1, [scratch1] + // mov [stack[out]], scratch0; add [stack[out]], scratch1 + assert_snapshot!(lines.join("\n"), @" + mov r11, qword ptr [rbp - 8] + mov r10, qword ptr [rbp - 0x10] + mov r10, qword ptr [r10] + mov r11, qword ptr [r11] + mov qword ptr [rbp - 0x18], r11 + add qword ptr [rbp - 0x18], r10 + "); + } + + #[test] + fn test_add_split_memory_output_can_compute_in_place() { + // stack[1] <- add cfp, stack[0] + let lines = split_binop_disasm_lines(BinOpKind::Add, CFP, stack_mem(0), stack_mem(1)); + + // Seed the output slot with the left register, then perform the add in place. + assert_snapshot!(lines.join("\n"), @" + mov r10, qword ptr [rbp - 8] + mov qword ptr [rbp - 0x10], r13 + add qword ptr [rbp - 0x10], r10 + "); + } + + #[test] + fn test_add_split_reg_mem_mem_when_right_equals_out() { + // stack[1] <- add cfp, stack[1] + // + // Preserve the original RHS/output value first, then seed the output + // slot with the left register and finish the add in place. + let lines = split_binop_disasm_lines(BinOpKind::Add, CFP, stack_mem(1), stack_mem(1)); + + assert_snapshot!(lines.join("\n"), @" + mov r10, qword ptr [rbp - 0x10] + mov qword ptr [rbp - 0x10], r13 + add qword ptr [rbp - 0x10], r10 + "); + } + + #[test] + #[should_panic(expected = "x86_scratch_split expects out to be a physical register or stack memory")] + fn test_binop_split_rejects_non_stack_memory_output() { + let _ = split_binop(BinOpKind::Add, CFP, C_RET_OPND, Opnd::mem(64, CFP, 8)); + } + + #[test] + fn test_add_split_mem_mem_mem_when_right_equals_out() { + // stack[1] <- add stack[0], stack[1] + // + // Preserve the original RHS/output value first, then reload the LHS and + // write the result back to the output stack slot. + let mut asm = split_binop(BinOpKind::Add, stack_mem(0), stack_mem(1), stack_mem(1)); + let mut cb = CodeBlock::new_dummy(); + for name in &asm.label_names { + cb.new_label(name.to_string()); + } + assert!(asm.x86_emit(&mut cb).is_some()); + + assert_disasm_snapshot!(cb.disasm(), @" + 0x0: mov r10, qword ptr [rbp - 0x10] + 0x4: mov r11, qword ptr [rbp - 8] + 0x8: mov qword ptr [rbp - 0x10], r11 + 0xc: add qword ptr [rbp - 0x10], r10 + "); + } + + #[test] + fn test_add_split_output_reg_reused_as_input_memory_base() { + // cfp <- add [cfp + 8], [cfp + 16] + // + // Preserve the RHS first because reusing `out` for the LHS would otherwise + // clobber the base register needed to address the RHS memory operand. + let mut asm = split_binop( + BinOpKind::Add, + Opnd::mem(64, CFP, 8), + Opnd::mem(64, CFP, 16), + CFP, + ); + let mut cb = CodeBlock::new_dummy(); + for name in &asm.label_names { + cb.new_label(name.to_string()); + } + assert!(asm.x86_emit(&mut cb).is_some()); + + assert_disasm_snapshot!(cb.disasm(), @" + 0x0: mov r10, qword ptr [r13 + 0x10] + 0x4: mov r13, qword ptr [r13 + 8] + 0x8: add r13, r10 + "); + assert_snapshot!(cb.hexdump(), @"4d8b55104d8b6d084d01d5"); + } + + #[test] + fn test_add_split_output_reg_reused_as_stack_indirect_memory_base() { + // cfp <- add mem[stack[0]], mem[stack[1]] + // + // The LHS lowering reuses `out` as the temporary base register for the + // stack-indirect address, then the RHS uses the normal scratch register. + let mut asm = split_binop( + BinOpKind::Add, + stack_indirect_mem(0), + stack_indirect_mem(1), + CFP, + ); + let mut cb = CodeBlock::new_dummy(); + for name in &asm.label_names { + cb.new_label(name.to_string()); + } + assert!(asm.x86_emit(&mut cb).is_some()); + + assert_disasm_snapshot!(cb.disasm(), @" + 0x0: mov r11, qword ptr [rbp - 8] + 0x4: mov r10, qword ptr [rbp - 0x10] + 0x8: mov r13, qword ptr [r11] + 0xb: add r13, qword ptr [r10] + "); + } + + #[test] + fn test_add_split_output_reg_reused_as_input_memory_base_with_imm() { + // cfp <- add 7, [cfp + 16] + // + // Preserve the RHS first because reusing `out` for the immediate + // materialization would otherwise clobber the base register needed for + // the memory operand. + let lines = split_binop_disasm_lines( + BinOpKind::Add, + Opnd::Imm(7), + Opnd::mem(64, CFP, 16), + CFP, + ); + + assert_snapshot!(lines.join("\n"), @" + mov r10, qword ptr [r13 + 0x10] + mov r13d, 7 + add r13, r10 + "); + } + + #[test] + fn test_binop_split_matrix() { + let left_cases = [ + ("reg", CFP), + ("mem_reg", Opnd::mem(64, C_RET_OPND, 8)), + ("mem_stack", stack_mem(0)), + ("mem_stack_indirect", stack_indirect_mem(0)), + ("imm32", Opnd::Imm(7)), + ("imm64", Opnd::UImm(0x1_0000_0000)), + ]; + let right_cases = [ + ("reg", C_RET_OPND), + ("mem_reg", Opnd::mem(64, CFP, 16)), + ("mem_stack", stack_mem(1)), + ("mem_stack_indirect", stack_indirect_mem(1)), + ("imm32", Opnd::Imm(9)), + ("imm64", Opnd::UImm(0x2_0000_0000)), + ]; + let out_cases = [ + ("out_reg", C_ARG_OPNDS[0]), + ("out_mem_stack", stack_mem(2)), + ]; + let alias_out_cases = [ + ("alias_out_cfp", CFP), + ("alias_out_reg", C_RET_OPND), + ("alias_out_mem_stack", stack_mem(1)), + ]; + let alias_mem_base_cases = [ + ( + "out_reused_as_left_mem_base", + Opnd::mem(64, CFP, 8), + C_RET_OPND, + CFP, + ), + ( + "out_reused_as_right_mem_base", + C_RET_OPND, + Opnd::mem(64, CFP, 16), + CFP, + ), + ( + "out_reused_as_both_mem_bases", + Opnd::mem(64, CFP, 8), + Opnd::mem(64, CFP, 16), + CFP, + ), + ]; + + for kind in [BinOpKind::Add, BinOpKind::Sub, BinOpKind::And, BinOpKind::Or, BinOpKind::Xor] { + for (left_name, left) in left_cases { + for (right_name, right) in right_cases { + for (out_name, out) in out_cases { + let case = format!("{left_name}/{right_name}/{out_name}"); + assert_split_binop_case(kind, left, right, out, &case); + } + } + } + + for (left_name, left) in left_cases { + for (alias_name, out) in alias_out_cases { + let case = format!("{left_name}/right_eq_out/{alias_name}"); + assert_split_binop_case(kind, left, out, out, &case); + } + } + + for (case, left, right, out) in alias_mem_base_cases { + assert_split_binop_case(kind, left, right, out, case); + } + } + } } From 8836334225221b1986fe424d9797c6f4d077fd9b Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Fri, 20 Mar 2026 16:38:41 -0400 Subject: [PATCH 02/21] ZJIT: Halve metadata memory usage (#16414) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use sparse sorted Vec for IseqProfile instead of dense pre-allocated Vecs Replace the two dense Vec fields (opnd_types and num_profiles) that were pre-allocated to iseq_size for every ISEQ with a single sorted Vec<(u32, ProfileEntry)> that only allocates entries for instructions that actually get profiled. Lookups use binary search. On Lobsters benchmark: zjit_alloc_bytes drops from 38.9 MB to 20.7 MB (46.8% reduction) with no performance regression. Use sparse storage for profiles and use u16 for counts instead of usize. Keep profiles in a sparse vec sorted by bytecode instruction index. ``` ┌─────────────────────┬─────────────────┬───────────────────┬────────┐ │ Metric │ upstream/master │ mb-sparse-profile │ Change │ ├─────────────────────┼─────────────────┼───────────────────┼────────┤ │ zjit_alloc_bytes │ 31.47 MB │ 14.99 MB │ −52.4% │ ├─────────────────────┼─────────────────┼───────────────────┼────────┤ │ total_mem_bytes │ 57.52 MB │ 41.05 MB │ −28.6% │ ├─────────────────────┼─────────────────┼───────────────────┼────────┤ │ compile_time │ 1,170ms │ 1,206ms │ +3.1% │ ├─────────────────────┼─────────────────┼───────────────────┼────────┤ │ profile_time │ 9ms │ 10ms │ ~same │ └─────────────────────┴─────────────────┴───────────────────┴────────┘ ``` --- zjit/src/distribution.rs | 12 ++--- zjit/src/options.rs | 2 +- zjit/src/payload.rs | 7 ++- zjit/src/profile.rs | 94 +++++++++++++++++++++++++++------------- 4 files changed, 74 insertions(+), 41 deletions(-) diff --git a/zjit/src/distribution.rs b/zjit/src/distribution.rs index 9b3920396a13b9..aa4667b9399c09 100644 --- a/zjit/src/distribution.rs +++ b/zjit/src/distribution.rs @@ -1,5 +1,7 @@ //! Type frequency distribution tracker. +use crate::options::NumProfiles; + /// This implementation was inspired by the type feedback module from Google's S6, which was /// written in C++ for use with Python. This is a new implementation in Rust created for use with /// Ruby instead of Python. @@ -8,9 +10,9 @@ pub struct Distribution { /// buckets and counts have the same length /// `buckets[0]` is always the most common item buckets: [T; N], - counts: [usize; N], + counts: [NumProfiles; N], /// if there is no more room, increment the fallback - other: usize, + other: NumProfiles, // TODO(max): Add count disparity, which can help determine when to reset the distribution } @@ -23,13 +25,13 @@ impl Distribution { for (bucket, count) in self.buckets.iter_mut().zip(self.counts.iter_mut()) { if *bucket == item || *count == 0 { *bucket = item; - *count += 1; + *count = count.saturating_add(1); // Keep the most frequent item at the front self.bubble_up(); return; } } - self.other += 1; + self.other = self.other.saturating_add(1); } /// Keep the highest counted bucket at index 0 @@ -87,7 +89,7 @@ impl Distributi assert!(first_count >= count, "First count should be the largest"); } } - let num_seen = dist.counts.iter().sum::() + dist.other; + let num_seen = dist.counts.iter().map(|&c| usize::from(c)).sum::() + usize::from(dist.other); let kind = if dist.other == 0 { // Seen <= N types total if dist.counts[0] == 0 { diff --git a/zjit/src/options.rs b/zjit/src/options.rs index acc965854b9b23..5da5fd2d706a5d 100644 --- a/zjit/src/options.rs +++ b/zjit/src/options.rs @@ -8,7 +8,7 @@ use std::collections::HashSet; /// Default --zjit-num-profiles const DEFAULT_NUM_PROFILES: NumProfiles = 5; -pub type NumProfiles = u32; +pub type NumProfiles = u16; /// Default --zjit-call-threshold. This should be large enough to avoid compiling /// warmup code, but small enough to perform well on micro-benchmarks. diff --git a/zjit/src/payload.rs b/zjit/src/payload.rs index 8540d5e35c498e..cb486975bd5d0b 100644 --- a/zjit/src/payload.rs +++ b/zjit/src/payload.rs @@ -14,9 +14,9 @@ pub struct IseqPayload { } impl IseqPayload { - fn new(iseq_size: u32) -> Self { + fn new() -> Self { Self { - profile: IseqProfile::new(iseq_size), + profile: IseqProfile::new(), versions: vec![], } } @@ -87,8 +87,7 @@ pub fn get_or_create_iseq_payload_ptr(iseq: IseqPtr) -> *mut IseqPayload { // We drop the payload with Box::from_raw when the GC frees the ISEQ and calls us. // NOTE(alan): Sometimes we read from an ISEQ without ever writing to it. // We allocate in those cases anyways. - let iseq_size = get_iseq_encoded_size(iseq); - let new_payload = IseqPayload::new(iseq_size); + let new_payload = IseqPayload::new(); let new_payload = Box::into_raw(Box::new(new_payload)); rb_iseq_set_zjit_payload(iseq, new_payload as VoidPtr); diff --git a/zjit/src/profile.rs b/zjit/src/profile.rs index 795aa6d60649e3..a4981156a6c756 100644 --- a/zjit/src/profile.rs +++ b/zjit/src/profile.rs @@ -104,8 +104,9 @@ fn profile_insn(bare_opcode: ruby_vminsn_type, ec: EcPtr) { } // Once we profile the instruction num_profiles times, we stop profiling it. - profile.num_profiles[profiler.insn_idx] = profile.num_profiles[profiler.insn_idx].saturating_add(1); - if profile.num_profiles[profiler.insn_idx] == get_option!(num_profiles) { + let entry = profile.entry_mut(profiler.insn_idx); + entry.num_profiles = entry.num_profiles.saturating_add(1); + if entry.num_profiles == get_option!(num_profiles) { unsafe { rb_zjit_iseq_insn_set(profiler.iseq, profiler.insn_idx as u32, bare_opcode); } } } @@ -118,12 +119,12 @@ pub type TypeDistributionSummary = DistributionSummary>, +struct ProfileEntry { + /// YARV instruction index + insn_idx: u32, + /// Type information of YARV instruction operands + opnd_types: Vec, + /// Number of profiled executions for this YARV instruction + num_profiles: NumProfiles, +} - /// Number of profiled executions for each YARV instruction, indexed by the instruction index - num_profiles: Vec, +#[derive(Debug)] +pub struct IseqProfile { + /// Sparse storage of per-instruction profile data, sorted by instruction index. + /// Only instructions that have actually been profiled have entries here. + entries: Vec, /// Method entries for `super` calls (stored as VALUE to be GC-safe) super_cme: HashMap } impl IseqProfile { - pub fn new(iseq_size: u32) -> Self { + pub fn new() -> Self { Self { - opnd_types: vec![vec![]; iseq_size as usize], - num_profiles: vec![0; iseq_size as usize], + entries: Vec::new(), super_cme: HashMap::new(), } } + /// Get or create a mutable profile entry for the given instruction index. + fn entry_mut(&mut self, insn_idx: usize) -> &mut ProfileEntry { + let idx = insn_idx as u32; + match self.entries.binary_search_by_key(&idx, |e| e.insn_idx) { + Ok(i) => &mut self.entries[i], + Err(i) => { + self.entries.insert(i, ProfileEntry { + insn_idx: idx, + opnd_types: Vec::new(), + num_profiles: 0, + }); + &mut self.entries[i] + } + } + } + + /// Get a profile entry for the given instruction index (read-only). + fn entry(&self, insn_idx: usize) -> Option<&ProfileEntry> { + let idx = insn_idx as u32; + self.entries.binary_search_by_key(&idx, |e| e.insn_idx) + .ok().map(|i| &self.entries[i]) + } + /// Get profiled operand types for a given instruction index pub fn get_operand_types(&self, insn_idx: usize) -> Option<&[TypeDistribution]> { - self.opnd_types.get(insn_idx).map(|v| &**v) + self.entry(insn_idx).map(|e| e.opnd_types.as_slice()).filter(|s| !s.is_empty()) } pub fn get_super_method_entry(&self, insn_idx: usize) -> Option<*const rb_callable_method_entry_t> { @@ -413,8 +445,8 @@ impl IseqProfile { /// Run a given callback with every object in IseqProfile pub fn each_object(&self, callback: impl Fn(VALUE)) { - for operands in &self.opnd_types { - for distribution in operands { + for entry in &self.entries { + for distribution in &entry.opnd_types { for profiled_type in distribution.each_item() { // If the type is a GC object, call the callback callback(profiled_type.class); @@ -431,8 +463,8 @@ impl IseqProfile { /// Run a given callback with a mutable reference to every object in IseqProfile. pub fn each_object_mut(&mut self, callback: impl Fn(&mut VALUE)) { - for operands in &mut self.opnd_types { - for distribution in operands { + for entry in &mut self.entries { + for distribution in &mut entry.opnd_types { for ref mut profiled_type in distribution.each_item_mut() { // If the type is a GC object, call the callback callback(&mut profiled_type.class); From cb15888a5d878afaad4301f67ee20d1b82ebfddf Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Fri, 20 Mar 2026 13:45:35 -0700 Subject: [PATCH 03/21] Fix make-snapshot: build dump_ast for mk_builtin_loader.rb (#16482) The make-snapshot process needs dump_ast (a C program) to generate .rbinc files via mk_builtin_loader.rb. Since CC=false in prereq.status prevents make from compiling C code, build dump_ast directly using the system compiler before running make prepare-package. The generated prism C sources and headers are created from ERB templates using BASERUBY before compilation, as they are not checked into git. --- tool/make-snapshot | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tool/make-snapshot b/tool/make-snapshot index 4af6a855ebb793..1b080d41683ac3 100755 --- a/tool/make-snapshot +++ b/tool/make-snapshot @@ -500,6 +500,36 @@ touch-unicode-files: ENV["CACHE_SAVE"] = "no" make = MAKE.new(args) return unless make.run("update-download") + # Build dump_ast for mk_builtin_loader.rb. CC=false in prereq.status + # prevents make from compiling it, so we build it directly here. + # Generate prism sources/headers from templates first, then compile. + dump_ast = vars["DUMP_AST"] + if dump_ast && !dump_ast.empty? && !File.exist?(dump_ast) && File.exist?("tool/dump_ast.c") + prism_template = "prism/templates/template.rb" + if File.exist?(prism_template) + baseruby_cmd = baseruby.shellsplit + Dir.glob("prism/templates/src/*.c.erb") do |erb| + name = File.basename(erb, ".erb") + out = "prism/#{name}" + system(*baseruby_cmd, prism_template, "src/#{name}", out) unless File.exist?(out) + end + %w[include/prism/ast.h include/prism/internal/diagnostic.h].each do |hdr| + out = "prism/#{hdr.delete_prefix("include/prism/")}" + FileUtils.mkpath(File.dirname(out)) + system(*baseruby_cmd, prism_template, hdr, out) unless File.exist?(out) + end + end + prism_srcs = Dir.glob("prism/*.c").reject {|f| %w[api_node extension].include?(File.basename(f, ".c"))} + unless prism_srcs.empty? + print "building dump_ast..." + if system("cc", "-o", dump_ast, "-Iprism", "-I.", "tool/dump_ast.c", *prism_srcs) + clean.add(dump_ast) + puts $colorize.pass(" done") + else + puts $colorize.fail(" failed") + end + end + end clean.push("rbconfig.rb", ".rbconfig.time", "enc.mk", "ext/ripper/y.output", ".revision.time") Dir.glob("**/*") do |dest| next unless File.symlink?(dest) From 58e5355626d45d566f2bf5e874702bad0a185535 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Fri, 20 Mar 2026 11:51:43 -0700 Subject: [PATCH 04/21] Revert "ZJIT: Prepare frame state before getivar calls" This reverts commit a5e2cbce97506d13f793667a967605dbe7c9e5f4. --- zjit/src/codegen.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index e51ddafe33798e..0dd35bdf7eaaac 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -630,7 +630,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio Insn::CCallVariadic { cfunc, recv, name, args, cme, state, blockiseq, return_type: _, elidable: _ } => { gen_ccall_variadic(jit, asm, *cfunc, *name, opnd!(recv), opnds!(args), *cme, *blockiseq, &function.frame_state(*state)) } - Insn::GetIvar { self_val, id, ic, state } => gen_getivar(jit, asm, opnd!(self_val), *id, *ic, &function.frame_state(*state)), + Insn::GetIvar { self_val, id, ic, state: _ } => gen_getivar(jit, asm, opnd!(self_val), *id, *ic), Insn::SetGlobal { id, val, state } => no_output!(gen_setglobal(jit, asm, *id, opnd!(val), &function.frame_state(*state))), Insn::GetGlobal { id, state } => gen_getglobal(jit, asm, *id, &function.frame_state(*state)), &Insn::IsBlockParamModified { ep } => gen_is_block_param_modified(asm, opnd!(ep)), @@ -1107,9 +1107,7 @@ fn gen_ccall_variadic( } /// Emit an uncached instance variable lookup -fn gen_getivar(jit: &mut JITState, asm: &mut Assembler, recv: Opnd, id: ID, ic: *const iseq_inline_iv_cache_entry, state: &FrameState) -> Opnd { - // rb_ivar_get can raise Ractor::IsolationError for class/module ivars from non-main Ractors - gen_prepare_non_leaf_call(jit, asm, state); +fn gen_getivar(jit: &mut JITState, asm: &mut Assembler, recv: Opnd, id: ID, ic: *const iseq_inline_iv_cache_entry) -> Opnd { if ic.is_null() { asm_ccall!(asm, rb_ivar_get, recv, id.0.into()) } else { From a53eb6bf68bad050c30f8bd3d7fb1a434bd55733 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Fri, 20 Mar 2026 14:20:02 -0700 Subject: [PATCH 05/21] Skip dump_ast dependency for .rbinc when BASERUBY is unavailable When building from a snapshot/tarball without BASERUBY, the .rbinc files are pre-generated and should not be rebuilt. However, DUMP_AST_TARGET was set to $(DUMP_AST) unconditionally, causing a freshly compiled dump_ast to trigger .rbinc regeneration which requires BASERUBY. Clear DUMP_AST_TARGET when HAVE_BASERUBY=no so the pre-generated .rbinc files are used as-is. --- configure.ac | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure.ac b/configure.ac index b9d465e0494d09..2a732c1d30eb21 100644 --- a/configure.ac +++ b/configure.ac @@ -115,6 +115,9 @@ AC_ARG_WITH(dump-ast, AS_HELP_STRING([--with-dump-ast=DUMP_AST], [use DUMP_AST as dump_ast; for cross-compiling with a host-built dump_ast]), [DUMP_AST=$withval DUMP_AST_TARGET='$(empty)'], [DUMP_AST='./dump_ast$(EXEEXT)' DUMP_AST_TARGET='$(DUMP_AST)']) +dnl Without baseruby, .rbinc files cannot be regenerated, so clear the +dnl dependency on dump_ast to avoid rebuilding pre-generated .rbinc files. +AS_IF([test "$HAVE_BASERUBY" = no], [DUMP_AST_TARGET='$(empty)']) AC_SUBST(X_DUMP_AST, "${DUMP_AST}") AC_SUBST(X_DUMP_AST_TARGET, "${DUMP_AST_TARGET}") From defbf494c282c327546cef00938ae2f34129ca09 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 19 Mar 2026 12:14:34 -0500 Subject: [PATCH 06/21] [ruby/prism] Swich identifiers to byte[] * JAVA_STRING_TYPE and related change to IDENTIFIER * TruffleRuby still uses java.lang.String Fixes https://github.com/ruby/prism/pull/4009 https://github.com/ruby/prism/commit/cbe91a3f36 --- prism/templates/template.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/prism/templates/template.rb b/prism/templates/template.rb index 8f7734dd43f001..be39c2f68255e1 100755 --- a/prism/templates/template.rb +++ b/prism/templates/template.rb @@ -12,7 +12,7 @@ module Template # :nodoc: all CHECK_FIELD_KIND = ENV.fetch("CHECK_FIELD_KIND", false) JAVA_BACKEND = ENV["PRISM_JAVA_BACKEND"] || "truffleruby" - JAVA_STRING_TYPE = JAVA_BACKEND == "jruby" ? "org.jruby.RubySymbol" : "String" + JAVA_IDENTIFIER_TYPE = JAVA_BACKEND == "truffleruby" ? "String" : "byte[]" INCLUDE_NODE_ID = !SERIALIZE_ONLY_SEMANTICS_FIELDS || JAVA_BACKEND == "jruby" COMMON_FLAGS_COUNT = 2 @@ -272,7 +272,7 @@ def call_seq_type end def java_type - JAVA_STRING_TYPE + JAVA_IDENTIFIER_TYPE end end @@ -292,7 +292,7 @@ def call_seq_type end def java_type - JAVA_STRING_TYPE + JAVA_IDENTIFIER_TYPE end end @@ -312,7 +312,7 @@ def call_seq_type end def java_type - "#{JAVA_STRING_TYPE}[]" + "#{JAVA_IDENTIFIER_TYPE}[]" end end From 32c5f01fa6e43b61d77fb7b7f6bee9ef8b2e53de Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Fri, 20 Mar 2026 09:59:53 -0500 Subject: [PATCH 07/21] [ruby/prism] Tweaks for byte[] identifiers * Allocate array of byte[] as byte[length][]. * Default JAVA_BACKEND to "default" with "truffleruby" the custom option. https://github.com/ruby/prism/commit/6ad180a00d --- prism/templates/template.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prism/templates/template.rb b/prism/templates/template.rb index be39c2f68255e1..5d1afc95065219 100755 --- a/prism/templates/template.rb +++ b/prism/templates/template.rb @@ -11,7 +11,7 @@ module Template # :nodoc: all REMOVE_ON_ERROR_TYPES = SERIALIZE_ONLY_SEMANTICS_FIELDS CHECK_FIELD_KIND = ENV.fetch("CHECK_FIELD_KIND", false) - JAVA_BACKEND = ENV["PRISM_JAVA_BACKEND"] || "truffleruby" + JAVA_BACKEND = ENV["PRISM_JAVA_BACKEND"] || "default" JAVA_IDENTIFIER_TYPE = JAVA_BACKEND == "truffleruby" ? "String" : "byte[]" INCLUDE_NODE_ID = !SERIALIZE_ONLY_SEMANTICS_FIELDS || JAVA_BACKEND == "jruby" From 6446aca07e96ef92019611e23041a262dd7872eb Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Fri, 20 Mar 2026 17:58:06 -0400 Subject: [PATCH 08/21] [ruby/prism] Revert "Switch identifiers to byte[]" https://github.com/ruby/prism/commit/efe36fbc46 --- prism/templates/template.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/prism/templates/template.rb b/prism/templates/template.rb index 5d1afc95065219..8f7734dd43f001 100755 --- a/prism/templates/template.rb +++ b/prism/templates/template.rb @@ -11,8 +11,8 @@ module Template # :nodoc: all REMOVE_ON_ERROR_TYPES = SERIALIZE_ONLY_SEMANTICS_FIELDS CHECK_FIELD_KIND = ENV.fetch("CHECK_FIELD_KIND", false) - JAVA_BACKEND = ENV["PRISM_JAVA_BACKEND"] || "default" - JAVA_IDENTIFIER_TYPE = JAVA_BACKEND == "truffleruby" ? "String" : "byte[]" + JAVA_BACKEND = ENV["PRISM_JAVA_BACKEND"] || "truffleruby" + JAVA_STRING_TYPE = JAVA_BACKEND == "jruby" ? "org.jruby.RubySymbol" : "String" INCLUDE_NODE_ID = !SERIALIZE_ONLY_SEMANTICS_FIELDS || JAVA_BACKEND == "jruby" COMMON_FLAGS_COUNT = 2 @@ -272,7 +272,7 @@ def call_seq_type end def java_type - JAVA_IDENTIFIER_TYPE + JAVA_STRING_TYPE end end @@ -292,7 +292,7 @@ def call_seq_type end def java_type - JAVA_IDENTIFIER_TYPE + JAVA_STRING_TYPE end end @@ -312,7 +312,7 @@ def call_seq_type end def java_type - "#{JAVA_IDENTIFIER_TYPE}[]" + "#{JAVA_STRING_TYPE}[]" end end From 5b4642bb31059d2de041b4f321ae9dbc924f79e2 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Fri, 20 Mar 2026 16:34:36 -0400 Subject: [PATCH 09/21] [ruby/prism] Prism.find Take a method, unbound method, proc, or thread backtrace location. This is our equivalent to RubyVM::AbstractSyntaxTree.of, and could be leveraged in something like error highlight. Note that this uses CRuby-specific APIs on CRuby, and falls back to using location-based APIs when those aren't available. https://github.com/ruby/prism/commit/02a93356a3 --- lib/prism.rb | 16 +- lib/prism/node_find.rb | 193 ++++++++++++++++++++++++ lib/prism/prism.gemspec | 4 + test/prism/newline_test.rb | 2 + test/prism/ruby/find_fixtures.rb | 70 +++++++++ test/prism/ruby/find_test.rb | 242 +++++++++++++++++++++++++++++++ 6 files changed, 526 insertions(+), 1 deletion(-) create mode 100644 lib/prism/node_find.rb create mode 100644 test/prism/ruby/find_fixtures.rb create mode 100644 test/prism/ruby/find_test.rb diff --git a/lib/prism.rb b/lib/prism.rb index 6b34ab12bfc6e5..8f0342724a30d3 100644 --- a/lib/prism.rb +++ b/lib/prism.rb @@ -23,6 +23,7 @@ module Prism autoload :InspectVisitor, "prism/inspect_visitor" autoload :LexCompat, "prism/lex_compat" autoload :MutationCompiler, "prism/mutation_compiler" + autoload :NodeFind, "prism/node_find" autoload :Pattern, "prism/pattern" autoload :Reflection, "prism/reflection" autoload :Relocation, "prism/relocation" @@ -34,7 +35,10 @@ module Prism # Some of these constants are not meant to be exposed, so marking them as # private here. - private_constant :LexCompat + if RUBY_ENGINE != "jruby" + private_constant :LexCompat + private_constant :NodeFind + end # Raised when requested to parse as the currently running Ruby version but Prism has no support for it. class CurrentVersionError < ArgumentError @@ -81,6 +85,16 @@ def self.load(source, serialized, freeze = false) Serialize.load_parse(source, serialized, freeze) end + # Given a Method, UnboundMethod, Proc, or Thread::Backtrace::Location, + # returns the Prism node representing it. On CRuby, this uses node_id for + # an exact match. On other implementations, it falls back to best-effort + # matching by source location line number. + #-- + #: (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable, ?rubyvm: bool) -> Node? + def self.find(callable, rubyvm: !!defined?(RubyVM)) + NodeFind.find(callable, rubyvm) + end + # @rbs! # VERSION: String # BACKEND: :CEXT | :FFI diff --git a/lib/prism/node_find.rb b/lib/prism/node_find.rb new file mode 100644 index 00000000000000..46dd598c054530 --- /dev/null +++ b/lib/prism/node_find.rb @@ -0,0 +1,193 @@ +# frozen_string_literal: true +# :markup: markdown +#-- +# rbs_inline: enabled + +module Prism + # Finds the Prism AST node corresponding to a given Method, UnboundMethod, + # Proc, or Thread::Backtrace::Location. On CRuby, uses node_id from the + # instruction sequence for an exact match. On other implementations, falls + # back to best-effort matching by source location line number. + # + # This module is autoloaded so that programs that don't use Prism.find don't + # pay for its definition. + module NodeFind # :nodoc: + # Find the node for the given callable or backtrace location. + #-- + #: (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable, bool rubyvm) -> Node? + #++ + def self.find(callable, rubyvm) + case callable + when Proc + if rubyvm + RubyVMCallableFind.new.find(callable) + elsif callable.lambda? + LineLambdaFind.new.find(callable) + else + LineProcFind.new.find(callable) + end + when Method, UnboundMethod + if rubyvm + RubyVMCallableFind.new.find(callable) + else + LineMethodFind.new.find(callable) + end + when Thread::Backtrace::Location + if rubyvm + RubyVMBacktraceLocationFind.new.find(callable) + else + LineBacktraceLocationFind.new.find(callable) + end + else + raise ArgumentError, "Expected a Method, UnboundMethod, Proc, or Thread::Backtrace::Location, got #{callable.class}" + end + end + + # Base class that handles parsing a file. + class Find + private + + # Parse the given file path, returning a ParseResult or nil. + #-- + #: (String? file) -> ParseResult? + + def parse_file(file) + return unless file && File.readable?(file) + result = Prism.parse_file(file) + result if result.success? + end + end + + # Finds the AST node for a Method, UnboundMethod, or Proc using the node_id + # from the instruction sequence. + class RubyVMCallableFind < Find + # Find the node for the given callable using the ISeq node_id. + #-- + #: (Method | UnboundMethod | Proc callable) -> Node? + + def find(callable) + return unless (source_location = callable.source_location) + return unless (result = parse_file(source_location[0])) + return unless (iseq = RubyVM::InstructionSequence.of(callable)) + + header = iseq.to_a[4] + return unless header[:parser] == :prism + + result.value.find { |node| node.node_id == header[:node_id] } + end + end + + # Finds the AST node for a Thread::Backtrace::Location using the node_id + # from the backtrace location. + class RubyVMBacktraceLocationFind < Find + # Find the node for the given backtrace location using node_id. + #-- + #: (Thread::Backtrace::Location location) -> Node? + + def find(location) + file = location.absolute_path || location.path + return unless (result = parse_file(file)) + return unless RubyVM::AbstractSyntaxTree.respond_to?(:node_id_for_backtrace_location) + + node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location) + + result.value.find { |node| node.node_id == node_id } + end + end + + # Finds the AST node for a Method or UnboundMethod using best-effort line + # matching. Used on non-CRuby implementations. + class LineMethodFind < Find + # Find the node for the given method by matching on name and line. + #-- + #: (Method | UnboundMethod callable) -> Node? + + def find(callable) + return unless (source_location = callable.source_location) + return unless (result = parse_file(source_location[0])) + + name = callable.name + start_line = source_location[1] + + result.value.find do |node| + case node + when DefNode + node.name == name && node.location.start_line == start_line + when CallNode + node.block.is_a?(BlockNode) && node.location.start_line == start_line + else + false + end + end + end + end + + # Finds the AST node for a lambda using best-effort line matching. Used + # on non-CRuby implementations. + class LineLambdaFind < Find + # Find the node for the given lambda by matching on line. + #-- + #: (Proc callable) -> Node? + + def find(callable) + return unless (source_location = callable.source_location) + return unless (result = parse_file(source_location[0])) + + start_line = source_location[1] + + result.value.find do |node| + case node + when LambdaNode + node.location.start_line == start_line + when CallNode + node.block.is_a?(BlockNode) && node.location.start_line == start_line + else + false + end + end + end + end + + # Finds the AST node for a non-lambda Proc using best-effort line + # matching. Used on non-CRuby implementations. + class LineProcFind < Find + # Find the node for the given proc by matching on line. + #-- + #: (Proc callable) -> Node? + + def find(callable) + return unless (source_location = callable.source_location) + return unless (result = parse_file(source_location[0])) + + start_line = source_location[1] + + result.value.find do |node| + case node + when ForNode + node.location.start_line == start_line + when CallNode + node.block.is_a?(BlockNode) && node.location.start_line == start_line + else + false + end + end + end + end + + # Finds the AST node for a Thread::Backtrace::Location using best-effort + # line matching. Used on non-CRuby implementations. + class LineBacktraceLocationFind < Find + # Find the node for the given backtrace location by matching on line. + #-- + #: (Thread::Backtrace::Location location) -> Node? + + def find(location) + file = location.absolute_path || location.path + return unless (result = parse_file(file)) + + start_line = location.lineno + result.value.find { |node| node.location.start_line == start_line } + end + end + end +end diff --git a/lib/prism/prism.gemspec b/lib/prism/prism.gemspec index d489a37af4798d..aac056b3f889e8 100644 --- a/lib/prism/prism.gemspec +++ b/lib/prism/prism.gemspec @@ -117,6 +117,7 @@ Gem::Specification.new do |spec| "lib/prism/lex_compat.rb", "lib/prism/mutation_compiler.rb", "lib/prism/node_ext.rb", + "lib/prism/node_find.rb", "lib/prism/node.rb", "lib/prism/parse_result.rb", "lib/prism/parse_result/comments.rb", @@ -158,6 +159,7 @@ Gem::Specification.new do |spec| "rbi/generated/prism/mutation_compiler.rbi", "rbi/generated/prism/node.rbi", "rbi/generated/prism/node_ext.rbi", + "rbi/generated/prism/node_find.rbi", "rbi/generated/prism/parse_result.rbi", "rbi/generated/prism/pattern.rbi", "rbi/generated/prism/reflection.rbi", @@ -172,6 +174,7 @@ Gem::Specification.new do |spec| "rbi/prism/translation/parser.rbi", "rbi/prism/translation/parser_versions.rbi", "rbi/prism/translation/ripper.rbi", + "rbi/rubyvm/node_find.rbi", "sig/generated/prism.rbs", "sig/generated/prism/compiler.rbs", "sig/generated/prism/desugar_compiler.rbs", @@ -183,6 +186,7 @@ Gem::Specification.new do |spec| "sig/generated/prism/mutation_compiler.rbs", "sig/generated/prism/node.rbs", "sig/generated/prism/node_ext.rbs", + "sig/generated/prism/node_find.rbs", "sig/generated/prism/parse_result.rbs", "sig/generated/prism/pattern.rbs", "sig/generated/prism/reflection.rbs", diff --git a/test/prism/newline_test.rb b/test/prism/newline_test.rb index fefe9def91f1e6..c8914b57dcfac8 100644 --- a/test/prism/newline_test.rb +++ b/test/prism/newline_test.rb @@ -17,6 +17,8 @@ class NewlineTest < TestCase result/breadth_first_search_test.rb result/static_literals_test.rb result/warnings_test.rb + ruby/find_fixtures.rb + ruby/find_test.rb ruby/parser_test.rb ruby/ruby_parser_test.rb ] diff --git a/test/prism/ruby/find_fixtures.rb b/test/prism/ruby/find_fixtures.rb new file mode 100644 index 00000000000000..df82cc700408b1 --- /dev/null +++ b/test/prism/ruby/find_fixtures.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +# Test fixtures for Prism.find. These must be in a separate file because +# source_location returns the file path and Prism.find re-parses the file. + +module Prism + module FindFixtures + module Methods + def simple_method + 42 + end + + def method_with_params(a, b, c) + a + b + c + end + + def method_with_block(&block) + block.call + end + + def self.singleton_method_fixture + :singleton + end + + def été + :utf8 + end + + def inline_method; :inline; end + end + + module Procs + SIMPLE_PROC = proc { 42 } + SIMPLE_LAMBDA = ->(x) { x * 2 } + MULTI_LINE_LAMBDA = lambda do |x| + x + 1 + end + DO_BLOCK_PROC = proc do |x| + x - 1 + end + end + + module DefineMethod + define_method(:dynamic) { |x| x + 1 } + end + + module ForLoop + items = [1, 2, 3] + for_proc = nil + o = Object.new + def o.each(&block) = block.call(block) + for for_proc in o; end + FOR_PROC = for_proc + end + + module MultipleOnLine + def self.first; end; def self.second; end + end + + module Errors + def self.divide(a, b) + a / b + end + + def self.call_undefined + undefined_method_call + end + end + end +end diff --git a/test/prism/ruby/find_test.rb b/test/prism/ruby/find_test.rb new file mode 100644 index 00000000000000..5b59113d30db69 --- /dev/null +++ b/test/prism/ruby/find_test.rb @@ -0,0 +1,242 @@ +# frozen_string_literal: true + +return if RUBY_ENGINE == "ruby" && RUBY_VERSION < "3.4" +return if defined?(RubyVM::InstructionSequence) && RubyVM::InstructionSequence.compile("").to_a[4][:parser] != :prism + +require_relative "../test_helper" +require_relative "find_fixtures" + +module Prism + class FindTest < TestCase + Fixtures = FindFixtures + FIXTURES_PATH = File.expand_path("find_fixtures.rb", __dir__) + + # === Method / UnboundMethod tests === + + def test_simple_method + assert_def_node Prism.find(Fixtures::Methods.instance_method(:simple_method)), :simple_method + end + + def test_method_with_params + node = Prism.find(Fixtures::Methods.instance_method(:method_with_params)) + assert_def_node node, :method_with_params + assert_equal 3, node.parameters.requireds.length + end + + def test_method_with_block_param + assert_def_node Prism.find(Fixtures::Methods.instance_method(:method_with_block)), :method_with_block + end + + def test_singleton_method + assert_def_node Prism.find(Fixtures::Methods.method(:singleton_method_fixture)), :singleton_method_fixture + end + + def test_utf8_method_name + assert_def_node Prism.find(Fixtures::Methods.instance_method(:été)), :été + end + + def test_inline_method + assert_def_node Prism.find(Fixtures::Methods.instance_method(:inline_method)), :inline_method + end + + def test_bound_method + obj = Object.new + obj.extend(Fixtures::Methods) + assert_def_node Prism.find(obj.method(:simple_method)), :simple_method + end + + # === Proc / Lambda tests === + + def test_simple_proc + assert_not_nil Prism.find(Fixtures::Procs::SIMPLE_PROC) + end + + def test_simple_lambda + assert_not_nil Prism.find(Fixtures::Procs::SIMPLE_LAMBDA) + end + + def test_multi_line_lambda + assert_not_nil Prism.find(Fixtures::Procs::MULTI_LINE_LAMBDA) + end + + def test_do_block_proc + assert_not_nil Prism.find(Fixtures::Procs::DO_BLOCK_PROC) + end + + # === define_method tests === + + def test_define_method + assert_not_nil Prism.find(Fixtures::DefineMethod.instance_method(:dynamic)) + end + + def test_define_method_bound + obj = Object.new + obj.extend(Fixtures::DefineMethod) + assert_not_nil Prism.find(obj.method(:dynamic)) + end + + # === for loop test === + + def test_for_loop_proc + node = Prism.find(Fixtures::ForLoop::FOR_PROC) + assert_instance_of ForNode, node + end + + # === Thread::Backtrace::Location tests === + + def test_backtrace_location_zero_division + location = zero_division_location + assert_not_nil location, "could not find backtrace location in fixtures file" + assert_not_nil Prism.find(location) + end + + def test_backtrace_location_name_error + location = begin + Fixtures::Errors.call_undefined + rescue NameError => e + fixture_backtrace_location(e) + end + + assert_not_nil location, "could not find backtrace location in fixtures file" + assert_not_nil Prism.find(location) + end + + def test_backtrace_location_from_caller + # caller_locations returns locations for the current call stack + location = caller_locations(0, 1).first + node = Prism.find(location) + assert_not_nil node + end + + def test_backtrace_location_eval_returns_nil + location = begin + eval("raise 'eval error'") + rescue RuntimeError => e + e.backtrace_locations.find { |loc| loc.path == "(eval)" || loc.label&.include?("eval") } + end + + # eval locations have no file on disk + assert_nil Prism.find(location) if location + end + + # === Edge cases === + + def test_nil_source_location + # Built-in methods have nil source_location + assert_nil Prism.find(method(:puts)) + end + + def test_argument_error_on_wrong_type + assert_raise(ArgumentError) { Prism.find("not a callable") } + assert_raise(ArgumentError) { Prism.find(42) } + assert_raise(ArgumentError) { Prism.find(nil) } + end + + def test_eval_returns_nil + # eval'd code has no file on disk + m = eval("proc { 1 }") + assert_nil Prism.find(m) + end + + def test_multiple_methods_on_same_line + assert_def_node Prism.find(Fixtures::MultipleOnLine.method(:first)), :first + assert_def_node Prism.find(Fixtures::MultipleOnLine.method(:second)), :second + end + + # === Fallback (line-based) tests via rubyvm: false === + + def test_fallback_simple_method + assert_def_node Prism.find(Fixtures::Methods.instance_method(:simple_method), rubyvm: false), :simple_method + end + + def test_fallback_singleton_method + assert_def_node Prism.find(Fixtures::Methods.method(:singleton_method_fixture), rubyvm: false), :singleton_method_fixture + end + + def test_fallback_lambda + node = Prism.find(Fixtures::Procs::SIMPLE_LAMBDA, rubyvm: false) + assert_instance_of LambdaNode, node + end + + def test_fallback_proc + node = Prism.find(Fixtures::Procs::SIMPLE_PROC, rubyvm: false) + assert_instance_of CallNode, node + assert node.block.is_a?(BlockNode) + end + + def test_fallback_define_method + node = Prism.find(Fixtures::DefineMethod.instance_method(:dynamic), rubyvm: false) + assert_instance_of CallNode, node + assert node.block.is_a?(BlockNode) + end + + def test_fallback_for_loop + node = Prism.find(Fixtures::ForLoop::FOR_PROC, rubyvm: false) + assert_instance_of ForNode, node + end + + def test_fallback_backtrace_location + location = zero_division_location + assert_not_nil location + node = Prism.find(location, rubyvm: false) + assert_not_nil node + assert_equal location.lineno, node.location.start_line + end + + # === Node identity with node_id (CRuby only) === + + if defined?(RubyVM::InstructionSequence) + def test_node_id_matches_iseq + m = Fixtures::Methods.instance_method(:simple_method) + node = Prism.find(m) + assert_equal node_id_of(m), node.node_id + end + + def test_node_id_for_lambda + node = Prism.find(Fixtures::Procs::SIMPLE_LAMBDA) + assert_equal node_id_of(Fixtures::Procs::SIMPLE_LAMBDA), node.node_id + end + + def test_node_id_for_proc + node = Prism.find(Fixtures::Procs::SIMPLE_PROC) + assert_equal node_id_of(Fixtures::Procs::SIMPLE_PROC), node.node_id + end + + def test_node_id_for_define_method + m = Fixtures::DefineMethod.instance_method(:dynamic) + node = Prism.find(m) + assert_equal node_id_of(m), node.node_id + end + + def test_node_id_for_backtrace_location + location = zero_division_location + assert_not_nil location + expected_node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location) + + node = Prism.find(location) + assert_equal expected_node_id, node.node_id + end + end + + private + + def assert_def_node(node, expected_name) + assert_instance_of DefNode, node + assert_equal expected_name, node.name + end + + def fixture_backtrace_location(exception) + exception.backtrace_locations.find { |loc| loc.path == FIXTURES_PATH } + end + + def zero_division_location + Fixtures::Errors.divide(1, 0) + rescue ZeroDivisionError => e + fixture_backtrace_location(e) + end + + def node_id_of(callable) + RubyVM::InstructionSequence.of(callable).to_a[4][:node_id] + end + end +end From f64f4b30b22e334139bb49fa6332265bc0bf6f98 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Mon, 16 Mar 2026 20:13:39 +0100 Subject: [PATCH 10/21] [ruby/prism] Ensure Source#offsets is set correctly in all cases * See https://github.com/ruby/prism/issues/3861 https://github.com/ruby/prism/commit/3f6014dc53 --- lib/prism/parse_result.rb | 3 ++- prism/templates/lib/prism/dsl.rb.erb | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/prism/parse_result.rb b/lib/prism/parse_result.rb index 4d1fa2c2965121..4f7bcf07d6bd01 100644 --- a/lib/prism/parse_result.rb +++ b/lib/prism/parse_result.rb @@ -26,7 +26,8 @@ class Source # source is a subset of a larger source or if this is an eval. offsets is an # array of byte offsets for the start of each line in the source code, which # can be calculated by iterating through the source code and recording the - # byte offset whenever a newline character is encountered. + # byte offset whenever a newline character is encountered. The first + # element is always 0 to mark the first line. #-- #: (String source, Integer start_line, Array[Integer] offsets) -> Source def self.for(source, start_line, offsets) diff --git a/prism/templates/lib/prism/dsl.rb.erb b/prism/templates/lib/prism/dsl.rb.erb index 6dcbbec100994a..95c4dac71a95a1 100644 --- a/prism/templates/lib/prism/dsl.rb.erb +++ b/prism/templates/lib/prism/dsl.rb.erb @@ -5,7 +5,7 @@ module Prism # The DSL module provides a set of methods that can be used to create prism # nodes in a more concise manner. For example, instead of writing: # - # source = Prism::Source.for("[1]", 1, []) + # source = Prism::Source.for("[1]", 1, [0]) # # Prism::ArrayNode.new( # source, @@ -62,7 +62,7 @@ module Prism #-- #: (String string) -> Source def source(string) - Source.for(string, 1, []) + Source.for(string, 1, build_offsets(string)) end # Create a new Location object. @@ -136,7 +136,7 @@ module Prism #-- #: () -> Source def default_source - Source.for("", 1, []) + Source.for("", 1, [0]) end # The default location object that gets attached to nodes if no location is @@ -154,5 +154,19 @@ module Prism def default_node(source, location) MissingNode.new(source, -1, location, 0) end + + private + + # Build the newline byte offset array for the given source string. + #-- + #: (String source) -> Array[Integer] + def build_offsets(source) + offsets = [0] + start = 0 + while (index = source.byteindex("\n", start)) + offsets << (start = index + 1) + end + offsets + end end end From f55d9e1945d56d356aa8bbfef1ace38ceeb65625 Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Fri, 20 Mar 2026 19:35:00 -0400 Subject: [PATCH 11/21] ZJIT: Add codegen for ArrayMax (#16411) Implements codegen for `ArrayMax` (opt_newarray_max) by calling the `rb_vm_opt_newarray_max` VM helper, following the same pattern as `ArrayHash` and `ArrayInclude`. --- zjit/src/codegen.rs | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index 0dd35bdf7eaaac..a5ca214de2c5c4 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -675,9 +675,8 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio &Insn::DupArrayInclude { ary, target, state } => gen_dup_array_include(jit, asm, ary, opnd!(target), &function.frame_state(state)), Insn::ArrayHash { elements, state } => gen_opt_newarray_hash(jit, asm, opnds!(elements), &function.frame_state(*state)), &Insn::IsA { val, class } => gen_is_a(jit, asm, opnd!(val), opnd!(class)), - &Insn::ArrayMax { state, .. } - | &Insn::Throw { state, .. } - => return Err(state), + &Insn::ArrayMax { ref elements, state } => gen_array_max(jit, asm, opnds!(elements), &function.frame_state(state)), + &Insn::Throw { state, .. } => return Err(state), &Insn::IfFalse { .. } | Insn::IfTrue { .. } | &Insn::Jump { .. } | Insn::Entries { .. } => unreachable!(), }; @@ -1824,6 +1823,32 @@ fn gen_opt_newarray_hash( ) } +/// Compile ArrayMax - find the maximum element among array elements +fn gen_array_max( + jit: &JITState, + asm: &mut Assembler, + elements: Vec, + state: &FrameState, +) -> lir::Opnd { + gen_prepare_non_leaf_call(jit, asm, state); + + let array_len: u32 = elements.len().try_into().expect("Unable to fit length of elements into u32"); + + // After gen_prepare_non_leaf_call, the elements are spilled to the Ruby stack. + // Get a pointer to the first element on the Ruby stack. + let stack_bottom = state.stack().len() - elements.len(); + let elements_ptr = asm.lea(Opnd::mem(VALUE_BITS, SP, stack_bottom as i32 * SIZEOF_VALUE_I32)); + + unsafe extern "C" { + fn rb_vm_opt_newarray_max(ec: EcPtr, num: u32, elts: *const VALUE) -> VALUE; + } + + asm.ccall( + rb_vm_opt_newarray_max as *const u8, + vec![EC, array_len.into(), elements_ptr], + ) +} + fn gen_array_include( jit: &JITState, asm: &mut Assembler, From e69e633363f0e99f05cc419a3f385f605811b16f Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Fri, 20 Mar 2026 20:11:31 -0400 Subject: [PATCH 12/21] ZJIT: Clean up getivar specialization code (#16475) Add reusable helpers for getting fields, making C calls, etc. De-indent a bunch of stuff. --- zjit/src/hir.rs | 183 +++++++++++++++++++++++------------------------- 1 file changed, 88 insertions(+), 95 deletions(-) diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 4471827986ce65..de63ac2f78c4ee 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -4214,6 +4214,93 @@ impl Function { }) } + fn load_ivar_c_call(&mut self, block: BlockId, recv: InsnId, ivar_index: u16) -> InsnId { + // NOTE: it's fine to use rb_ivar_get_at_no_ractor_check because + // getinstancevariable does assume_single_ractor_mode() + let ivar_index_insn = self.push_insn(block, Insn::Const { val: Const::CUInt16(ivar_index) }); + self.push_insn(block, Insn::CCall { + cfunc: rb_ivar_get_at_no_ractor_check as *const u8, + recv, + args: vec![ivar_index_insn], + name: ID!(rb_ivar_get_at_no_ractor_check), + return_type: types::BasicObject, + elidable: true }) + } + + fn load_ivar_heap(&mut self, block: BlockId, recv: InsnId, id: ID, ivar_index: u16) -> InsnId { + // See ROBJECT_FIELDS() from include/ruby/internal/core/robject.h + let ptr = self.push_insn(block, Insn::LoadField { + recv, id: ID!(_as_heap), + offset: ROBJECT_OFFSET_AS_HEAP_FIELDS as i32, + return_type: types::CPtr, + }); + let offset = SIZEOF_VALUE_I32 * ivar_index as i32; + self.push_insn(block, Insn::LoadField { + recv: ptr, id, offset, + return_type: types::BasicObject, + }) + } + + fn load_ivar_embedded(&mut self, block: BlockId, recv: InsnId, id: ID, ivar_index: u16) -> InsnId { + // See ROBJECT_FIELDS() from include/ruby/internal/core/robject.h + let offset = ROBJECT_OFFSET_AS_ARY as i32 + + (SIZEOF_VALUE * ivar_index.to_usize()) as i32; + self.push_insn(block, Insn::LoadField { + recv, id, offset, + return_type: types::BasicObject, + }) + } + + fn load_ivar_from_fields(&mut self, block: BlockId, recv: InsnId, is_embedded: bool, id: ID, ivar_index: u16) -> InsnId { + if is_embedded { + return self.load_ivar_embedded(block, recv, id, ivar_index); + } else { + return self.load_ivar_heap(block, recv, id, ivar_index); + } + } + + fn load_ivar(&mut self, block: BlockId, self_val: InsnId, recv_type: ProfiledType, id: ID, state: InsnId) -> InsnId { + let mut ivar_index: u16 = 0; + if ! unsafe { rb_shape_get_iv_index(recv_type.shape().0, id, &mut ivar_index) } { + // If there is no IVAR index, then the ivar was undefined when we + // entered the compiler. That means we can just return nil for this + // shape + iv name + return self.push_insn(block, Insn::Const { val: Const::Value(Qnil) }); + } + if recv_type.flags().is_t_class_or_module() { + // Class/module ivar: load from prime classext's fields_obj + if !self.assume_root_box(block, state) { + // Non-root box active: fall back to C call + // NOTE: it's fine to use rb_ivar_get_at_no_ractor_check because + // getinstancevariable does assume_single_ractor_mode() + return self.load_ivar_c_call(block, self_val, ivar_index); + } + // Root box only: load directly from prime classext + let fields_obj = self.push_insn(block, Insn::LoadField { + recv: self_val, id: ID!(_fields_obj), + offset: RCLASS_OFFSET_PRIME_FIELDS_OBJ as i32, + return_type: types::RubyValue, + }); + return self.load_ivar_from_fields(block, fields_obj, recv_type.flags().is_fields_embedded(), id, ivar_index); + } + if recv_type.flags().is_typed_data() { + // Typed T_DATA: load from fields_obj at fixed offset in RTypedData + let fields_obj = self.push_insn(block, Insn::LoadField { + recv: self_val, id: ID!(_fields_obj), + offset: RTYPEDDATA_OFFSET_FIELDS_OBJ as i32, + return_type: types::RubyValue, + }); + return self.load_ivar_from_fields(block, fields_obj, recv_type.flags().is_fields_embedded(), id, ivar_index); + } + if recv_type.flags().is_t_object() { + return self.load_ivar_from_fields(block, self_val, recv_type.flags().is_embedded(), id, ivar_index); + } + // Non-T_OBJECT, non-class/module, non-typed-data: fall back to C call + // NOTE: it's fine to use rb_ivar_get_at_no_ractor_check because + // getinstancevariable does assume_single_ractor_mode() + return self.load_ivar_c_call(block, self_val, ivar_index); + } + fn optimize_getivar(&mut self) { for block in self.rpo() { let old_insns = std::mem::take(&mut self.blocks[block.0].insns); @@ -4241,101 +4328,7 @@ impl Function { let self_val = self.push_insn(block, Insn::GuardType { val: self_val, guard_type: types::HeapBasicObject, state }); let shape = self.load_shape(block, self_val); self.guard_shape(block, shape, recv_type.shape(), state); - let mut ivar_index: u16 = 0; - let replacement = if ! unsafe { rb_shape_get_iv_index(recv_type.shape().0, id, &mut ivar_index) } { - // If there is no IVAR index, then the ivar was undefined when we - // entered the compiler. That means we can just return nil for this - // shape + iv name - self.push_insn(block, Insn::Const { val: Const::Value(Qnil) }) - } else if recv_type.flags().is_t_class_or_module() { - // Class/module ivar: load from prime classext's fields_obj - if self.assume_root_box(block, state) { - // Root box only: load directly from prime classext - let fields_obj = self.push_insn(block, Insn::LoadField { - recv: self_val, id: ID!(_fields_obj), - offset: RCLASS_OFFSET_PRIME_FIELDS_OBJ as i32, - return_type: types::RubyValue, - }); - if recv_type.flags().is_fields_embedded() { - let offset = ROBJECT_OFFSET_AS_ARY as i32 - + (SIZEOF_VALUE * ivar_index.to_usize()) as i32; - self.push_insn(block, Insn::LoadField { - recv: fields_obj, id, offset, - return_type: types::BasicObject, - }) - } else { - let ptr = self.push_insn(block, Insn::LoadField { - recv: fields_obj, id: ID!(_as_heap), - offset: ROBJECT_OFFSET_AS_HEAP_FIELDS as i32, - return_type: types::CPtr, - }); - let offset = SIZEOF_VALUE_I32 * ivar_index as i32; - self.push_insn(block, Insn::LoadField { - recv: ptr, id, offset, - return_type: types::BasicObject, - }) - } - } else { - // Non-root box active: fall back to C call - // NOTE: it's fine to use rb_ivar_get_at_no_ractor_check because - // getinstancevariable does assume_single_ractor_mode() - let ivar_index_insn = self.push_insn(block, Insn::Const { val: Const::CUInt16(ivar_index as u16) }); - self.push_insn(block, Insn::CCall { - cfunc: rb_ivar_get_at_no_ractor_check as *const u8, - recv: self_val, - args: vec![ivar_index_insn], - name: ID!(rb_ivar_get_at_no_ractor_check), - return_type: types::BasicObject, - elidable: true }) - } - } else if recv_type.flags().is_typed_data() { - // Typed T_DATA: load from fields_obj at fixed offset in RTypedData - let fields_obj = self.push_insn(block, Insn::LoadField { - recv: self_val, id: ID!(_fields_obj), - offset: RTYPEDDATA_OFFSET_FIELDS_OBJ as i32, - return_type: types::RubyValue, - }); - if recv_type.flags().is_fields_embedded() { - let offset = ROBJECT_OFFSET_AS_ARY as i32 - + (SIZEOF_VALUE * ivar_index.to_usize()) as i32; - self.push_insn(block, Insn::LoadField { - recv: fields_obj, id, offset, - return_type: types::BasicObject, - }) - } else { - let ptr = self.push_insn(block, Insn::LoadField { - recv: fields_obj, id: ID!(_as_heap), - offset: ROBJECT_OFFSET_AS_HEAP_FIELDS as i32, - return_type: types::CPtr, - }); - let offset = SIZEOF_VALUE_I32 * ivar_index as i32; - self.push_insn(block, Insn::LoadField { - recv: ptr, id, offset, - return_type: types::BasicObject, - }) - } - } else if !recv_type.flags().is_t_object() { - // Non-T_OBJECT, non-class/module, non-typed-data: fall back to C call - // NOTE: it's fine to use rb_ivar_get_at_no_ractor_check because - // getinstancevariable does assume_single_ractor_mode() - let ivar_index_insn = self.push_insn(block, Insn::Const { val: Const::CUInt16(ivar_index as u16) }); - self.push_insn(block, Insn::CCall { - cfunc: rb_ivar_get_at_no_ractor_check as *const u8, - recv: self_val, - args: vec![ivar_index_insn], - name: ID!(rb_ivar_get_at_no_ractor_check), - return_type: types::BasicObject, - elidable: true }) - } else if recv_type.flags().is_embedded() { - // See ROBJECT_FIELDS() from include/ruby/internal/core/robject.h - let offset = ROBJECT_OFFSET_AS_ARY as i32 + (SIZEOF_VALUE * ivar_index.to_usize()) as i32; - self.push_insn(block, Insn::LoadField { recv: self_val, id, offset, return_type: types::BasicObject }) - } else { - let as_heap = self.push_insn(block, Insn::LoadField { recv: self_val, id: ID!(_as_heap), offset: ROBJECT_OFFSET_AS_HEAP_FIELDS as i32, return_type: types::CPtr }); - - let offset = SIZEOF_VALUE_I32 * ivar_index as i32; - self.push_insn(block, Insn::LoadField { recv: as_heap, id, offset, return_type: types::BasicObject }) - }; + let replacement = self.load_ivar(block, self_val, recv_type, id, state); self.make_equal_to(insn_id, replacement); } Insn::DefinedIvar { self_val, id, pushval, state } => { From 6b2f2097c2bfd71555c11fefca005263b21e6942 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 20 Mar 2026 17:19:51 -0700 Subject: [PATCH 13/21] ZJIT: Unbox fixnum constants at compile time. (#16484) I noticed that we're generating machine code that unboxes fixnum constants. Since the fixnum is constant, and known at compile time, we can unbox it eagerly and convert it to a Const CInt64 --- zjit/src/hir.rs | 7 ++++ zjit/src/hir/opt_tests.rs | 83 ++++++++++++++++++++++++++++----------- 2 files changed, 66 insertions(+), 24 deletions(-) diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index de63ac2f78c4ee..ebdf044a920daf 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -5064,6 +5064,13 @@ impl Function { _ => insn_id, } } + Insn::UnboxFixnum { val } => { + let recv_type = self.type_of(val); + match recv_type.fixnum_value() { + Some(val) => self.new_insn(Insn::Const { val: Const::CInt64(val) }), + _ => insn_id, + } + }, Insn::GuardBitEquals { val, expected, .. } => { let recv_type = self.type_of(val); if recv_type.has_value(expected) { diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs index aa706f7ddaeadd..bc3f92b83ab923 100644 --- a/zjit/src/hir/opt_tests.rs +++ b/zjit/src/hir/opt_tests.rs @@ -990,6 +990,41 @@ mod hir_opt_tests { "); } + #[test] + fn test_fold_unbox_fixnum() { + eval(" + def test(arr) = arr[0] + test([1,2,3]) + "); + assert_snapshot!(hir_string("test"), @" + fn test@:2: + bb1(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:CPtr = LoadSP + v3:BasicObject = LoadField v2, :arr@0x1000 + Jump bb3(v1, v3) + bb2(): + EntryPoint JIT(0) + v6:BasicObject = LoadArg :self@0 + v7:BasicObject = LoadArg :arr@1 + Jump bb3(v6, v7) + bb3(v9:BasicObject, v10:BasicObject): + v15:Fixnum[0] = Const Value(0) + PatchPoint NoSingletonClass(Array@0x1008) + PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018) + v27:ArrayExact = GuardType v10, ArrayExact + v34:CInt64[0] = Const CInt64(0) + v29:CInt64 = ArrayLength v27 + v30:CInt64[0] = GuardLess v34, v29 + v31:CInt64[0] = Const CInt64(0) + v32:CInt64[0] = GuardGreaterEq v30, v31 + v33:BasicObject = ArrayAref v27, v32 + CheckInterrupts + Return v33 + "); + } + #[test] fn neq_with_side_effect_not_elided () { let result = eval(" @@ -2249,9 +2284,9 @@ mod hir_opt_tests { PatchPoint NoSingletonClass(Array@0x1008) PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018) v27:ArrayExact = GuardType v10, ArrayExact - v28:CInt64[0] = UnboxFixnum v15 + v34:CInt64[0] = Const CInt64(0) v29:CInt64 = ArrayLength v27 - v30:CInt64[0] = GuardLess v28, v29 + v30:CInt64[0] = GuardLess v34, v29 v31:CInt64[0] = Const CInt64(0) v32:CInt64[0] = GuardGreaterEq v30, v31 v33:BasicObject = ArrayAref v27, v32 @@ -5960,9 +5995,9 @@ mod hir_opt_tests { v12:Fixnum[0] = Const Value(0) PatchPoint NoSingletonClass(Array@0x1010) PatchPoint MethodRedefined(Array@0x1010, []@0x1018, cme:0x1020) - v27:CInt64[0] = UnboxFixnum v12 + v33:CInt64[0] = Const CInt64(0) v28:CInt64 = ArrayLength v23 - v29:CInt64[0] = GuardLess v27, v28 + v29:CInt64[0] = GuardLess v33, v28 v30:CInt64[0] = Const CInt64(0) v31:CInt64[0] = GuardGreaterEq v29, v30 v32:BasicObject = ArrayAref v23, v31 @@ -5994,14 +6029,14 @@ mod hir_opt_tests { v13:Fixnum[1] = Const Value(1) PatchPoint NoSingletonClass(Array@0x1008) PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018) - v25:CInt64[1] = UnboxFixnum v13 + v31:CInt64[1] = Const CInt64(1) v26:CInt64 = ArrayLength v11 - v27:CInt64[1] = GuardLess v25, v26 + v27:CInt64[1] = GuardLess v31, v26 v28:CInt64[0] = Const CInt64(0) v29:CInt64[1] = GuardGreaterEq v27, v28 - v31:Fixnum[5] = Const Value(5) + v32:Fixnum[5] = Const Value(5) CheckInterrupts - Return v31 + Return v32 "); } @@ -6026,14 +6061,14 @@ mod hir_opt_tests { v13:Fixnum[-3] = Const Value(-3) PatchPoint NoSingletonClass(Array@0x1008) PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018) - v25:CInt64[-3] = UnboxFixnum v13 + v31:CInt64[-3] = Const CInt64(-3) v26:CInt64 = ArrayLength v11 - v27:CInt64[-3] = GuardLess v25, v26 + v27:CInt64[-3] = GuardLess v31, v26 v28:CInt64[0] = Const CInt64(0) v29:CInt64[-3] = GuardGreaterEq v27, v28 - v31:Fixnum[4] = Const Value(4) + v32:Fixnum[4] = Const Value(4) CheckInterrupts - Return v31 + Return v32 "); } @@ -6058,14 +6093,14 @@ mod hir_opt_tests { v13:Fixnum[-10] = Const Value(-10) PatchPoint NoSingletonClass(Array@0x1008) PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018) - v25:CInt64[-10] = UnboxFixnum v13 + v31:CInt64[-10] = Const CInt64(-10) v26:CInt64 = ArrayLength v11 - v27:CInt64[-10] = GuardLess v25, v26 + v27:CInt64[-10] = GuardLess v31, v26 v28:CInt64[0] = Const CInt64(0) v29:CInt64[-10] = GuardGreaterEq v27, v28 - v31:NilClass = Const Value(nil) + v32:NilClass = Const Value(nil) CheckInterrupts - Return v31 + Return v32 "); } @@ -6090,14 +6125,14 @@ mod hir_opt_tests { v13:Fixnum[10] = Const Value(10) PatchPoint NoSingletonClass(Array@0x1008) PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018) - v25:CInt64[10] = UnboxFixnum v13 + v31:CInt64[10] = Const CInt64(10) v26:CInt64 = ArrayLength v11 - v27:CInt64[10] = GuardLess v25, v26 + v27:CInt64[10] = GuardLess v31, v26 v28:CInt64[0] = Const CInt64(0) v29:CInt64[10] = GuardGreaterEq v27, v28 - v31:NilClass = Const Value(nil) + v32:NilClass = Const Value(nil) CheckInterrupts - Return v31 + Return v32 "); } @@ -8324,9 +8359,9 @@ mod hir_opt_tests { v19:Fixnum[0] = Const Value(0) PatchPoint NoSingletonClass(Array@0x1008) PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018) - v31:CInt64[0] = UnboxFixnum v19 + v37:CInt64[0] = Const CInt64(0) v32:CInt64 = ArrayLength v14 - v33:CInt64[0] = GuardLess v31, v32 + v33:CInt64[0] = GuardLess v37, v32 v34:CInt64[0] = Const CInt64(0) v35:CInt64[0] = GuardGreaterEq v33, v34 v36:BasicObject = ArrayAref v14, v35 @@ -8706,9 +8741,9 @@ mod hir_opt_tests { v34:CUInt64 = LoadField v33, :_rbasic_flags@0x1040 v35:CUInt64 = GuardNoBitsSet v34, RUBY_FL_FREEZE=CUInt64(2048) v37:CUInt64 = GuardNoBitsSet v34, RUBY_ELTS_SHARED=CUInt64(4096) - v38:CInt64[1] = UnboxFixnum v17 + v45:CInt64[1] = Const CInt64(1) v39:CInt64 = ArrayLength v33 - v40:CInt64[1] = GuardLess v38, v39 + v40:CInt64[1] = GuardLess v45, v39 v41:CInt64[0] = Const CInt64(0) v42:CInt64[1] = GuardGreaterEq v40, v41 ArrayAset v33, v42, v19 From 229a7ae7a97ff796984ebccdbc2040f9d805306e Mon Sep 17 00:00:00 2001 From: BurdetteLamar Date: Mon, 16 Mar 2026 18:34:56 +0100 Subject: [PATCH 14/21] [DOC] Tweaks for Pathname#+ --- pathname_builtin.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pathname_builtin.rb b/pathname_builtin.rb index c85a865d1a8d86..3a676680c27db9 100644 --- a/pathname_builtin.rb +++ b/pathname_builtin.rb @@ -750,8 +750,14 @@ def ascend # call-seq: # self + other -> new_pathname # - # Returns a new \Pathname object; - # argument +other+ may be a string or another pathname. + # Returns a new \Pathname object based on the content of +self+ and +other+; + # argument +other+ may be a String, a File, a Dir, or another \Pathname: + # + # pn = Pathname.new('foo') # => # + # pn + 'bar' # => # + # pn + File.new('LEGAL') # => # + # pn + Dir.new('lib') # => # + # pn + Pathname.new('bar') # => # # # When +other+ specifies a relative path (see #relative?), # it is combined with +self+ to form a new pathname: From e6cf66a8e765a42f4abc03b967752f38bf789d94 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Fri, 20 Mar 2026 19:16:08 -0400 Subject: [PATCH 15/21] [PRISM] Remove checked-in generated file --- .gitignore | 1 + prism/json.c | 5723 -------------------------------------------------- 2 files changed, 1 insertion(+), 5723 deletions(-) delete mode 100644 prism/json.c diff --git a/.gitignore b/.gitignore index c8319fc9e2bbd2..11e635412d5d94 100644 --- a/.gitignore +++ b/.gitignore @@ -268,6 +268,7 @@ lcov*.info /prism/api_node.c /prism/ast.h /prism/diagnostic.c +/prism/json.c /prism/node.c /prism/prettyprint.c /prism/serialize.c diff --git a/prism/json.c b/prism/json.c deleted file mode 100644 index 72975db72480d7..00000000000000 --- a/prism/json.c +++ /dev/null @@ -1,5723 +0,0 @@ -/*----------------------------------------------------------------------------*/ -/* This file is generated by the templates/template.rb script and should not */ -/* be modified manually. See */ -/* templates/src/json.c.erb */ -/* if you are looking to modify the */ -/* template */ -/*----------------------------------------------------------------------------*/ - -#include "prism/json.h" - -// Ensure this translation unit is never empty, even when JSON is excluded. -typedef int pm_json_unused_t; - -#ifndef PRISM_EXCLUDE_JSON - -#include "prism/internal/buffer.h" -#include "prism/internal/constant_pool.h" -#include "prism/internal/integer.h" -#include "prism/internal/parser.h" - -#include - -static void -pm_dump_json_constant(pm_buffer_t *buffer, const pm_parser_t *parser, pm_constant_id_t constant_id) { - const pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id); - pm_buffer_append_byte(buffer, '"'); - pm_buffer_append_source(buffer, constant->start, constant->length, PM_BUFFER_ESCAPING_JSON); - pm_buffer_append_byte(buffer, '"'); -} - -static void -pm_dump_json_location(pm_buffer_t *buffer, const pm_location_t *location) { - pm_buffer_append_format(buffer, "{\"start\":%" PRIu32 ",\"length\":%" PRIu32 "}", location->start, location->length); -} - -/** - * Dump JSON to the given buffer. - */ -void -pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node) { - switch (PM_NODE_TYPE(node)) { - case PM_ALIAS_GLOBAL_VARIABLE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"AliasGlobalVariableNode\",\"location\":", 45); - - const pm_alias_global_variable_node_t *cast = (const pm_alias_global_variable_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the new_name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"new_name\":", 11); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->new_name); - - // Dump the old_name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"old_name\":", 11); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->old_name); - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_ALIAS_METHOD_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"AliasMethodNode\",\"location\":", 37); - - const pm_alias_method_node_t *cast = (const pm_alias_method_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the new_name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"new_name\":", 11); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->new_name); - - // Dump the old_name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"old_name\":", 11); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->old_name); - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_ALTERNATION_PATTERN_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"AlternationPatternNode\",\"location\":", 44); - - const pm_alternation_pattern_node_t *cast = (const pm_alternation_pattern_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the left field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"left\":", 7); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->left); - - // Dump the right field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"right\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->right); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_AND_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"AndNode\",\"location\":", 29); - - const pm_and_node_t *cast = (const pm_and_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the left field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"left\":", 7); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->left); - - // Dump the right field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"right\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->right); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_ARGUMENTS_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ArgumentsNode\",\"location\":", 35); - - const pm_arguments_node_t *cast = (const pm_arguments_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the ArgumentsNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"CONTAINS_FORWARDING\"", 21); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"CONTAINS_KEYWORDS\"", 19); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"CONTAINS_KEYWORD_SPLAT\"", 24); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"CONTAINS_SPLAT\"", 16); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"CONTAINS_MULTIPLE_SPLATS\"", 26); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the arguments field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"arguments\":", 12); - const pm_node_list_t *arguments = &cast->arguments; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < arguments->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, arguments->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_ARRAY_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ArrayNode\",\"location\":", 31); - - const pm_array_node_t *cast = (const pm_array_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the ArrayNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"CONTAINS_SPLAT\"", 16); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the elements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"elements\":", 11); - const pm_node_list_t *elements = &cast->elements; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < elements->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, elements->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - if (cast->opening_loc.length != 0) { - pm_dump_json_location(buffer, &cast->opening_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - if (cast->closing_loc.length != 0) { - pm_dump_json_location(buffer, &cast->closing_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_ARRAY_PATTERN_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ArrayPatternNode\",\"location\":", 38); - - const pm_array_pattern_node_t *cast = (const pm_array_pattern_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the constant field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"constant\":", 11); - if (cast->constant != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the requireds field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"requireds\":", 12); - const pm_node_list_t *requireds = &cast->requireds; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < requireds->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, requireds->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the rest field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rest\":", 7); - if (cast->rest != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the posts field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"posts\":", 8); - const pm_node_list_t *posts = &cast->posts; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < posts->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, posts->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - if (cast->opening_loc.length != 0) { - pm_dump_json_location(buffer, &cast->opening_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - if (cast->closing_loc.length != 0) { - pm_dump_json_location(buffer, &cast->closing_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_ASSOC_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"AssocNode\",\"location\":", 31); - - const pm_assoc_node_t *cast = (const pm_assoc_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the key field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"key\":", 6); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->key); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - if (cast->operator_loc.length != 0) { - pm_dump_json_location(buffer, &cast->operator_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_ASSOC_SPLAT_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"AssocSplatNode\",\"location\":", 36); - - const pm_assoc_splat_node_t *cast = (const pm_assoc_splat_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - if (cast->value != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_BACK_REFERENCE_READ_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"BackReferenceReadNode\",\"location\":", 43); - - const pm_back_reference_read_node_t *cast = (const pm_back_reference_read_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_BEGIN_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"BeginNode\",\"location\":", 31); - - const pm_begin_node_t *cast = (const pm_begin_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the begin_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"begin_keyword_loc\":", 20); - if (cast->begin_keyword_loc.length != 0) { - pm_dump_json_location(buffer, &cast->begin_keyword_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - if (cast->statements != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the rescue_clause field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rescue_clause\":", 16); - if (cast->rescue_clause != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->rescue_clause); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the else_clause field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"else_clause\":", 14); - if (cast->else_clause != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->else_clause); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the ensure_clause field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ensure_clause\":", 16); - if (cast->ensure_clause != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->ensure_clause); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the end_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); - if (cast->end_keyword_loc.length != 0) { - pm_dump_json_location(buffer, &cast->end_keyword_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_BLOCK_ARGUMENT_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"BlockArgumentNode\",\"location\":", 39); - - const pm_block_argument_node_t *cast = (const pm_block_argument_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the expression field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"expression\":", 13); - if (cast->expression != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_BLOCK_LOCAL_VARIABLE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"BlockLocalVariableNode\",\"location\":", 44); - - const pm_block_local_variable_node_t *cast = (const pm_block_local_variable_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the ParameterFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_BLOCK_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"BlockNode\",\"location\":", 31); - - const pm_block_node_t *cast = (const pm_block_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the locals field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"locals\":", 9); - const pm_constant_id_list_t *locals = &cast->locals; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < locals->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json_constant(buffer, parser, locals->ids[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the parameters field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"parameters\":", 13); - if (cast->parameters != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->parameters); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the body field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"body\":", 7); - if (cast->body != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->body); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_BLOCK_PARAMETER_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"BlockParameterNode\",\"location\":", 40); - - const pm_block_parameter_node_t *cast = (const pm_block_parameter_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the ParameterFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - if (cast->name != PM_CONSTANT_ID_UNSET) { - pm_dump_json_constant(buffer, parser, cast->name); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - if (cast->name_loc.length != 0) { - pm_dump_json_location(buffer, &cast->name_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_BLOCK_PARAMETERS_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"BlockParametersNode\",\"location\":", 41); - - const pm_block_parameters_node_t *cast = (const pm_block_parameters_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the parameters field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"parameters\":", 13); - if (cast->parameters != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->parameters); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the locals field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"locals\":", 9); - const pm_node_list_t *locals = &cast->locals; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < locals->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, locals->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - if (cast->opening_loc.length != 0) { - pm_dump_json_location(buffer, &cast->opening_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - if (cast->closing_loc.length != 0) { - pm_dump_json_location(buffer, &cast->closing_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_BREAK_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"BreakNode\",\"location\":", 31); - - const pm_break_node_t *cast = (const pm_break_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the arguments field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"arguments\":", 12); - if (cast->arguments != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CALL_AND_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"CallAndWriteNode\",\"location\":", 38); - - const pm_call_and_write_node_t *cast = (const pm_call_and_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the CallNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the receiver field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"receiver\":", 11); - if (cast->receiver != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the call_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); - if (cast->call_operator_loc.length != 0) { - pm_dump_json_location(buffer, &cast->call_operator_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the message_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"message_loc\":", 14); - if (cast->message_loc.length != 0) { - pm_dump_json_location(buffer, &cast->message_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the read_name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"read_name\":", 12); - pm_dump_json_constant(buffer, parser, cast->read_name); - - // Dump the write_name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"write_name\":", 13); - pm_dump_json_constant(buffer, parser, cast->write_name); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CALL_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"CallNode\",\"location\":", 30); - - const pm_call_node_t *cast = (const pm_call_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the CallNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the receiver field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"receiver\":", 11); - if (cast->receiver != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the call_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); - if (cast->call_operator_loc.length != 0) { - pm_dump_json_location(buffer, &cast->call_operator_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the message_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"message_loc\":", 14); - if (cast->message_loc.length != 0) { - pm_dump_json_location(buffer, &cast->message_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - if (cast->opening_loc.length != 0) { - pm_dump_json_location(buffer, &cast->opening_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the arguments field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"arguments\":", 12); - if (cast->arguments != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - if (cast->closing_loc.length != 0) { - pm_dump_json_location(buffer, &cast->closing_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the equal_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"equal_loc\":", 12); - if (cast->equal_loc.length != 0) { - pm_dump_json_location(buffer, &cast->equal_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the block field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"block\":", 8); - if (cast->block != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CALL_OPERATOR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"CallOperatorWriteNode\",\"location\":", 43); - - const pm_call_operator_write_node_t *cast = (const pm_call_operator_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the CallNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the receiver field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"receiver\":", 11); - if (cast->receiver != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the call_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); - if (cast->call_operator_loc.length != 0) { - pm_dump_json_location(buffer, &cast->call_operator_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the message_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"message_loc\":", 14); - if (cast->message_loc.length != 0) { - pm_dump_json_location(buffer, &cast->message_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the read_name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"read_name\":", 12); - pm_dump_json_constant(buffer, parser, cast->read_name); - - // Dump the write_name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"write_name\":", 13); - pm_dump_json_constant(buffer, parser, cast->write_name); - - // Dump the binary_operator field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator\":", 18); - pm_dump_json_constant(buffer, parser, cast->binary_operator); - - // Dump the binary_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); - pm_dump_json_location(buffer, &cast->binary_operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CALL_OR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"CallOrWriteNode\",\"location\":", 37); - - const pm_call_or_write_node_t *cast = (const pm_call_or_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the CallNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the receiver field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"receiver\":", 11); - if (cast->receiver != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the call_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); - if (cast->call_operator_loc.length != 0) { - pm_dump_json_location(buffer, &cast->call_operator_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the message_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"message_loc\":", 14); - if (cast->message_loc.length != 0) { - pm_dump_json_location(buffer, &cast->message_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the read_name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"read_name\":", 12); - pm_dump_json_constant(buffer, parser, cast->read_name); - - // Dump the write_name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"write_name\":", 13); - pm_dump_json_constant(buffer, parser, cast->write_name); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CALL_TARGET_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"CallTargetNode\",\"location\":", 36); - - const pm_call_target_node_t *cast = (const pm_call_target_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the CallNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the receiver field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"receiver\":", 11); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); - - // Dump the call_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); - pm_dump_json_location(buffer, &cast->call_operator_loc); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the message_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"message_loc\":", 14); - pm_dump_json_location(buffer, &cast->message_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CAPTURE_PATTERN_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"CapturePatternNode\",\"location\":", 40); - - const pm_capture_pattern_node_t *cast = (const pm_capture_pattern_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the target field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"target\":", 9); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->target); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CASE_MATCH_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"CaseMatchNode\",\"location\":", 35); - - const pm_case_match_node_t *cast = (const pm_case_match_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the predicate field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"predicate\":", 12); - if (cast->predicate != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the conditions field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"conditions\":", 13); - const pm_node_list_t *conditions = &cast->conditions; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < conditions->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, conditions->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the else_clause field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"else_clause\":", 14); - if (cast->else_clause != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->else_clause); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the case_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"case_keyword_loc\":", 19); - pm_dump_json_location(buffer, &cast->case_keyword_loc); - - // Dump the end_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); - pm_dump_json_location(buffer, &cast->end_keyword_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CASE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"CaseNode\",\"location\":", 30); - - const pm_case_node_t *cast = (const pm_case_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the predicate field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"predicate\":", 12); - if (cast->predicate != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the conditions field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"conditions\":", 13); - const pm_node_list_t *conditions = &cast->conditions; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < conditions->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, conditions->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the else_clause field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"else_clause\":", 14); - if (cast->else_clause != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->else_clause); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the case_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"case_keyword_loc\":", 19); - pm_dump_json_location(buffer, &cast->case_keyword_loc); - - // Dump the end_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); - pm_dump_json_location(buffer, &cast->end_keyword_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CLASS_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ClassNode\",\"location\":", 31); - - const pm_class_node_t *cast = (const pm_class_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the locals field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"locals\":", 9); - const pm_constant_id_list_t *locals = &cast->locals; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < locals->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json_constant(buffer, parser, locals->ids[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the class_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"class_keyword_loc\":", 20); - pm_dump_json_location(buffer, &cast->class_keyword_loc); - - // Dump the constant_path field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"constant_path\":", 16); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant_path); - - // Dump the inheritance_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"inheritance_operator_loc\":", 27); - if (cast->inheritance_operator_loc.length != 0) { - pm_dump_json_location(buffer, &cast->inheritance_operator_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the superclass field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"superclass\":", 13); - if (cast->superclass != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->superclass); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the body field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"body\":", 7); - if (cast->body != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->body); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the end_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); - pm_dump_json_location(buffer, &cast->end_keyword_loc); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CLASS_VARIABLE_AND_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableAndWriteNode\",\"location\":", 47); - - const pm_class_variable_and_write_node_t *cast = (const pm_class_variable_and_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableOperatorWriteNode\",\"location\":", 52); - - const pm_class_variable_operator_write_node_t *cast = (const pm_class_variable_operator_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the binary_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); - pm_dump_json_location(buffer, &cast->binary_operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the binary_operator field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator\":", 18); - pm_dump_json_constant(buffer, parser, cast->binary_operator); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CLASS_VARIABLE_OR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableOrWriteNode\",\"location\":", 46); - - const pm_class_variable_or_write_node_t *cast = (const pm_class_variable_or_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CLASS_VARIABLE_READ_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableReadNode\",\"location\":", 43); - - const pm_class_variable_read_node_t *cast = (const pm_class_variable_read_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CLASS_VARIABLE_TARGET_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableTargetNode\",\"location\":", 45); - - const pm_class_variable_target_node_t *cast = (const pm_class_variable_target_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CLASS_VARIABLE_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableWriteNode\",\"location\":", 44); - - const pm_class_variable_write_node_t *cast = (const pm_class_variable_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CONSTANT_AND_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ConstantAndWriteNode\",\"location\":", 42); - - const pm_constant_and_write_node_t *cast = (const pm_constant_and_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CONSTANT_OPERATOR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ConstantOperatorWriteNode\",\"location\":", 47); - - const pm_constant_operator_write_node_t *cast = (const pm_constant_operator_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the binary_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); - pm_dump_json_location(buffer, &cast->binary_operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the binary_operator field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator\":", 18); - pm_dump_json_constant(buffer, parser, cast->binary_operator); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CONSTANT_OR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ConstantOrWriteNode\",\"location\":", 41); - - const pm_constant_or_write_node_t *cast = (const pm_constant_or_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CONSTANT_PATH_AND_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathAndWriteNode\",\"location\":", 46); - - const pm_constant_path_and_write_node_t *cast = (const pm_constant_path_and_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the target field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"target\":", 9); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->target); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CONSTANT_PATH_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathNode\",\"location\":", 38); - - const pm_constant_path_node_t *cast = (const pm_constant_path_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the parent field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"parent\":", 9); - if (cast->parent != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->parent); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - if (cast->name != PM_CONSTANT_ID_UNSET) { - pm_dump_json_constant(buffer, parser, cast->name); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the delimiter_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"delimiter_loc\":", 16); - pm_dump_json_location(buffer, &cast->delimiter_loc); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CONSTANT_PATH_OPERATOR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathOperatorWriteNode\",\"location\":", 51); - - const pm_constant_path_operator_write_node_t *cast = (const pm_constant_path_operator_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the target field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"target\":", 9); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->target); - - // Dump the binary_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); - pm_dump_json_location(buffer, &cast->binary_operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the binary_operator field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator\":", 18); - pm_dump_json_constant(buffer, parser, cast->binary_operator); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CONSTANT_PATH_OR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathOrWriteNode\",\"location\":", 45); - - const pm_constant_path_or_write_node_t *cast = (const pm_constant_path_or_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the target field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"target\":", 9); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->target); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CONSTANT_PATH_TARGET_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathTargetNode\",\"location\":", 44); - - const pm_constant_path_target_node_t *cast = (const pm_constant_path_target_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the parent field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"parent\":", 9); - if (cast->parent != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->parent); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - if (cast->name != PM_CONSTANT_ID_UNSET) { - pm_dump_json_constant(buffer, parser, cast->name); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the delimiter_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"delimiter_loc\":", 16); - pm_dump_json_location(buffer, &cast->delimiter_loc); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CONSTANT_PATH_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathWriteNode\",\"location\":", 43); - - const pm_constant_path_write_node_t *cast = (const pm_constant_path_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the target field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"target\":", 9); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->target); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CONSTANT_READ_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ConstantReadNode\",\"location\":", 38); - - const pm_constant_read_node_t *cast = (const pm_constant_read_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CONSTANT_TARGET_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ConstantTargetNode\",\"location\":", 40); - - const pm_constant_target_node_t *cast = (const pm_constant_target_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_CONSTANT_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ConstantWriteNode\",\"location\":", 39); - - const pm_constant_write_node_t *cast = (const pm_constant_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_DEF_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"DefNode\",\"location\":", 29); - - const pm_def_node_t *cast = (const pm_def_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the receiver field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"receiver\":", 11); - if (cast->receiver != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the parameters field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"parameters\":", 13); - if (cast->parameters != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->parameters); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the body field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"body\":", 7); - if (cast->body != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->body); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the locals field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"locals\":", 9); - const pm_constant_id_list_t *locals = &cast->locals; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < locals->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json_constant(buffer, parser, locals->ids[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the def_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"def_keyword_loc\":", 18); - pm_dump_json_location(buffer, &cast->def_keyword_loc); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - if (cast->operator_loc.length != 0) { - pm_dump_json_location(buffer, &cast->operator_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the lparen_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"lparen_loc\":", 13); - if (cast->lparen_loc.length != 0) { - pm_dump_json_location(buffer, &cast->lparen_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the rparen_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rparen_loc\":", 13); - if (cast->rparen_loc.length != 0) { - pm_dump_json_location(buffer, &cast->rparen_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the equal_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"equal_loc\":", 12); - if (cast->equal_loc.length != 0) { - pm_dump_json_location(buffer, &cast->equal_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the end_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); - if (cast->end_keyword_loc.length != 0) { - pm_dump_json_location(buffer, &cast->end_keyword_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_DEFINED_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"DefinedNode\",\"location\":", 33); - - const pm_defined_node_t *cast = (const pm_defined_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the lparen_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"lparen_loc\":", 13); - if (cast->lparen_loc.length != 0) { - pm_dump_json_location(buffer, &cast->lparen_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the rparen_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rparen_loc\":", 13); - if (cast->rparen_loc.length != 0) { - pm_dump_json_location(buffer, &cast->rparen_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_ELSE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ElseNode\",\"location\":", 30); - - const pm_else_node_t *cast = (const pm_else_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the else_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"else_keyword_loc\":", 19); - pm_dump_json_location(buffer, &cast->else_keyword_loc); - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - if (cast->statements != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the end_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); - if (cast->end_keyword_loc.length != 0) { - pm_dump_json_location(buffer, &cast->end_keyword_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_EMBEDDED_STATEMENTS_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"EmbeddedStatementsNode\",\"location\":", 44); - - const pm_embedded_statements_node_t *cast = (const pm_embedded_statements_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - if (cast->statements != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_EMBEDDED_VARIABLE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"EmbeddedVariableNode\",\"location\":", 42); - - const pm_embedded_variable_node_t *cast = (const pm_embedded_variable_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the variable field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"variable\":", 11); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->variable); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_ENSURE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"EnsureNode\",\"location\":", 32); - - const pm_ensure_node_t *cast = (const pm_ensure_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the ensure_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ensure_keyword_loc\":", 21); - pm_dump_json_location(buffer, &cast->ensure_keyword_loc); - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - if (cast->statements != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the end_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); - pm_dump_json_location(buffer, &cast->end_keyword_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_FALSE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"FalseNode\",\"location\":", 31); - - const pm_false_node_t *cast = (const pm_false_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_FIND_PATTERN_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"FindPatternNode\",\"location\":", 37); - - const pm_find_pattern_node_t *cast = (const pm_find_pattern_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the constant field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"constant\":", 11); - if (cast->constant != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the left field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"left\":", 7); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->left); - - // Dump the requireds field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"requireds\":", 12); - const pm_node_list_t *requireds = &cast->requireds; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < requireds->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, requireds->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the right field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"right\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->right); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - if (cast->opening_loc.length != 0) { - pm_dump_json_location(buffer, &cast->opening_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - if (cast->closing_loc.length != 0) { - pm_dump_json_location(buffer, &cast->closing_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_FLIP_FLOP_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"FlipFlopNode\",\"location\":", 34); - - const pm_flip_flop_node_t *cast = (const pm_flip_flop_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the RangeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"EXCLUDE_END\"", 13); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the left field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"left\":", 7); - if (cast->left != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->left); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the right field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"right\":", 8); - if (cast->right != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->right); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_FLOAT_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"FloatNode\",\"location\":", 31); - - const pm_float_node_t *cast = (const pm_float_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_buffer_append_format(buffer, "%f", cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_FOR_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ForNode\",\"location\":", 29); - - const pm_for_node_t *cast = (const pm_for_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the index field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"index\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->index); - - // Dump the collection field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"collection\":", 13); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->collection); - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - if (cast->statements != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the for_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"for_keyword_loc\":", 18); - pm_dump_json_location(buffer, &cast->for_keyword_loc); - - // Dump the in_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"in_keyword_loc\":", 17); - pm_dump_json_location(buffer, &cast->in_keyword_loc); - - // Dump the do_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"do_keyword_loc\":", 17); - if (cast->do_keyword_loc.length != 0) { - pm_dump_json_location(buffer, &cast->do_keyword_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the end_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); - pm_dump_json_location(buffer, &cast->end_keyword_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_FORWARDING_ARGUMENTS_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ForwardingArgumentsNode\",\"location\":", 45); - - const pm_forwarding_arguments_node_t *cast = (const pm_forwarding_arguments_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_FORWARDING_PARAMETER_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ForwardingParameterNode\",\"location\":", 45); - - const pm_forwarding_parameter_node_t *cast = (const pm_forwarding_parameter_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_FORWARDING_SUPER_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ForwardingSuperNode\",\"location\":", 41); - - const pm_forwarding_super_node_t *cast = (const pm_forwarding_super_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the block field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"block\":", 8); - if (cast->block != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_GLOBAL_VARIABLE_AND_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableAndWriteNode\",\"location\":", 48); - - const pm_global_variable_and_write_node_t *cast = (const pm_global_variable_and_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableOperatorWriteNode\",\"location\":", 53); - - const pm_global_variable_operator_write_node_t *cast = (const pm_global_variable_operator_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the binary_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); - pm_dump_json_location(buffer, &cast->binary_operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the binary_operator field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator\":", 18); - pm_dump_json_constant(buffer, parser, cast->binary_operator); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_GLOBAL_VARIABLE_OR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableOrWriteNode\",\"location\":", 47); - - const pm_global_variable_or_write_node_t *cast = (const pm_global_variable_or_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_GLOBAL_VARIABLE_READ_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableReadNode\",\"location\":", 44); - - const pm_global_variable_read_node_t *cast = (const pm_global_variable_read_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_GLOBAL_VARIABLE_TARGET_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableTargetNode\",\"location\":", 46); - - const pm_global_variable_target_node_t *cast = (const pm_global_variable_target_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_GLOBAL_VARIABLE_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableWriteNode\",\"location\":", 45); - - const pm_global_variable_write_node_t *cast = (const pm_global_variable_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_HASH_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"HashNode\",\"location\":", 30); - - const pm_hash_node_t *cast = (const pm_hash_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the elements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"elements\":", 11); - const pm_node_list_t *elements = &cast->elements; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < elements->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, elements->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_HASH_PATTERN_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"HashPatternNode\",\"location\":", 37); - - const pm_hash_pattern_node_t *cast = (const pm_hash_pattern_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the constant field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"constant\":", 11); - if (cast->constant != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the elements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"elements\":", 11); - const pm_node_list_t *elements = &cast->elements; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < elements->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, elements->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the rest field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rest\":", 7); - if (cast->rest != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - if (cast->opening_loc.length != 0) { - pm_dump_json_location(buffer, &cast->opening_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - if (cast->closing_loc.length != 0) { - pm_dump_json_location(buffer, &cast->closing_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_IF_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"IfNode\",\"location\":", 28); - - const pm_if_node_t *cast = (const pm_if_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the if_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"if_keyword_loc\":", 17); - if (cast->if_keyword_loc.length != 0) { - pm_dump_json_location(buffer, &cast->if_keyword_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the predicate field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"predicate\":", 12); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate); - - // Dump the then_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"then_keyword_loc\":", 19); - if (cast->then_keyword_loc.length != 0) { - pm_dump_json_location(buffer, &cast->then_keyword_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - if (cast->statements != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the subsequent field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"subsequent\":", 13); - if (cast->subsequent != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->subsequent); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the end_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); - if (cast->end_keyword_loc.length != 0) { - pm_dump_json_location(buffer, &cast->end_keyword_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_IMAGINARY_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ImaginaryNode\",\"location\":", 35); - - const pm_imaginary_node_t *cast = (const pm_imaginary_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the numeric field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"numeric\":", 10); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->numeric); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_IMPLICIT_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ImplicitNode\",\"location\":", 34); - - const pm_implicit_node_t *cast = (const pm_implicit_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_IMPLICIT_REST_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ImplicitRestNode\",\"location\":", 38); - - const pm_implicit_rest_node_t *cast = (const pm_implicit_rest_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_IN_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"InNode\",\"location\":", 28); - - const pm_in_node_t *cast = (const pm_in_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the pattern field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"pattern\":", 10); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->pattern); - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - if (cast->statements != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the in_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"in_loc\":", 9); - pm_dump_json_location(buffer, &cast->in_loc); - - // Dump the then_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"then_loc\":", 11); - if (cast->then_loc.length != 0) { - pm_dump_json_location(buffer, &cast->then_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INDEX_AND_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"IndexAndWriteNode\",\"location\":", 39); - - const pm_index_and_write_node_t *cast = (const pm_index_and_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the CallNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the receiver field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"receiver\":", 11); - if (cast->receiver != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the call_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); - if (cast->call_operator_loc.length != 0) { - pm_dump_json_location(buffer, &cast->call_operator_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the arguments field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"arguments\":", 12); - if (cast->arguments != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - // Dump the block field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"block\":", 8); - if (cast->block != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INDEX_OPERATOR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"IndexOperatorWriteNode\",\"location\":", 44); - - const pm_index_operator_write_node_t *cast = (const pm_index_operator_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the CallNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the receiver field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"receiver\":", 11); - if (cast->receiver != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the call_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); - if (cast->call_operator_loc.length != 0) { - pm_dump_json_location(buffer, &cast->call_operator_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the arguments field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"arguments\":", 12); - if (cast->arguments != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - // Dump the block field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"block\":", 8); - if (cast->block != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the binary_operator field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator\":", 18); - pm_dump_json_constant(buffer, parser, cast->binary_operator); - - // Dump the binary_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); - pm_dump_json_location(buffer, &cast->binary_operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INDEX_OR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"IndexOrWriteNode\",\"location\":", 38); - - const pm_index_or_write_node_t *cast = (const pm_index_or_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the CallNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the receiver field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"receiver\":", 11); - if (cast->receiver != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the call_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20); - if (cast->call_operator_loc.length != 0) { - pm_dump_json_location(buffer, &cast->call_operator_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the arguments field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"arguments\":", 12); - if (cast->arguments != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - // Dump the block field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"block\":", 8); - if (cast->block != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INDEX_TARGET_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"IndexTargetNode\",\"location\":", 37); - - const pm_index_target_node_t *cast = (const pm_index_target_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the CallNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the receiver field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"receiver\":", 11); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the arguments field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"arguments\":", 12); - if (cast->arguments != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - // Dump the block field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"block\":", 8); - if (cast->block != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INSTANCE_VARIABLE_AND_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableAndWriteNode\",\"location\":", 50); - - const pm_instance_variable_and_write_node_t *cast = (const pm_instance_variable_and_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableOperatorWriteNode\",\"location\":", 55); - - const pm_instance_variable_operator_write_node_t *cast = (const pm_instance_variable_operator_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the binary_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); - pm_dump_json_location(buffer, &cast->binary_operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the binary_operator field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator\":", 18); - pm_dump_json_constant(buffer, parser, cast->binary_operator); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INSTANCE_VARIABLE_OR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableOrWriteNode\",\"location\":", 49); - - const pm_instance_variable_or_write_node_t *cast = (const pm_instance_variable_or_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INSTANCE_VARIABLE_READ_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableReadNode\",\"location\":", 46); - - const pm_instance_variable_read_node_t *cast = (const pm_instance_variable_read_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INSTANCE_VARIABLE_TARGET_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableTargetNode\",\"location\":", 48); - - const pm_instance_variable_target_node_t *cast = (const pm_instance_variable_target_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INSTANCE_VARIABLE_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableWriteNode\",\"location\":", 47); - - const pm_instance_variable_write_node_t *cast = (const pm_instance_variable_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INTEGER_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"IntegerNode\",\"location\":", 33); - - const pm_integer_node_t *cast = (const pm_integer_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the IntegerBaseFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_BINARY)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"BINARY\"", 8); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_DECIMAL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"DECIMAL\"", 9); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_OCTAL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"OCTAL\"", 7); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_HEXADECIMAL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"HEXADECIMAL\"", 13); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_integer_string(buffer, &cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INTERPOLATED_MATCH_LAST_LINE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedMatchLastLineNode\",\"location\":", 51); - - const pm_interpolated_match_last_line_node_t *cast = (const pm_interpolated_match_last_line_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the RegularExpressionFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"IGNORE_CASE\"", 13); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"EXTENDED\"", 10); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"MULTI_LINE\"", 12); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ONCE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ONCE\"", 6); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"EUC_JP\"", 8); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ASCII_8BIT\"", 12); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"WINDOWS_31J\"", 13); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"UTF_8\"", 7); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the parts field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"parts\":", 8); - const pm_node_list_t *parts = &cast->parts; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < parts->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, parts->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedRegularExpressionNode\",\"location\":", 55); - - const pm_interpolated_regular_expression_node_t *cast = (const pm_interpolated_regular_expression_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the RegularExpressionFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"IGNORE_CASE\"", 13); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"EXTENDED\"", 10); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"MULTI_LINE\"", 12); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ONCE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ONCE\"", 6); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"EUC_JP\"", 8); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ASCII_8BIT\"", 12); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"WINDOWS_31J\"", 13); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"UTF_8\"", 7); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the parts field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"parts\":", 8); - const pm_node_list_t *parts = &cast->parts; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < parts->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, parts->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INTERPOLATED_STRING_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedStringNode\",\"location\":", 44); - - const pm_interpolated_string_node_t *cast = (const pm_interpolated_string_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the InterpolatedStringNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FROZEN\"", 8); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"MUTABLE\"", 9); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - if (cast->opening_loc.length != 0) { - pm_dump_json_location(buffer, &cast->opening_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the parts field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"parts\":", 8); - const pm_node_list_t *parts = &cast->parts; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < parts->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, parts->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - if (cast->closing_loc.length != 0) { - pm_dump_json_location(buffer, &cast->closing_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INTERPOLATED_SYMBOL_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedSymbolNode\",\"location\":", 44); - - const pm_interpolated_symbol_node_t *cast = (const pm_interpolated_symbol_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - if (cast->opening_loc.length != 0) { - pm_dump_json_location(buffer, &cast->opening_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the parts field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"parts\":", 8); - const pm_node_list_t *parts = &cast->parts; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < parts->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, parts->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - if (cast->closing_loc.length != 0) { - pm_dump_json_location(buffer, &cast->closing_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_INTERPOLATED_X_STRING_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedXStringNode\",\"location\":", 45); - - const pm_interpolated_x_string_node_t *cast = (const pm_interpolated_x_string_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the parts field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"parts\":", 8); - const pm_node_list_t *parts = &cast->parts; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < parts->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, parts->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_IT_LOCAL_VARIABLE_READ_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ItLocalVariableReadNode\",\"location\":", 45); - - const pm_it_local_variable_read_node_t *cast = (const pm_it_local_variable_read_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_IT_PARAMETERS_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ItParametersNode\",\"location\":", 38); - - const pm_it_parameters_node_t *cast = (const pm_it_parameters_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_KEYWORD_HASH_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"KeywordHashNode\",\"location\":", 37); - - const pm_keyword_hash_node_t *cast = (const pm_keyword_hash_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the KeywordHashNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"SYMBOL_KEYS\"", 13); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the elements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"elements\":", 11); - const pm_node_list_t *elements = &cast->elements; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < elements->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, elements->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_KEYWORD_REST_PARAMETER_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"KeywordRestParameterNode\",\"location\":", 46); - - const pm_keyword_rest_parameter_node_t *cast = (const pm_keyword_rest_parameter_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the ParameterFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - if (cast->name != PM_CONSTANT_ID_UNSET) { - pm_dump_json_constant(buffer, parser, cast->name); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - if (cast->name_loc.length != 0) { - pm_dump_json_location(buffer, &cast->name_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_LAMBDA_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"LambdaNode\",\"location\":", 32); - - const pm_lambda_node_t *cast = (const pm_lambda_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the locals field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"locals\":", 9); - const pm_constant_id_list_t *locals = &cast->locals; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < locals->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json_constant(buffer, parser, locals->ids[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - // Dump the parameters field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"parameters\":", 13); - if (cast->parameters != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->parameters); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the body field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"body\":", 7); - if (cast->body != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->body); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_LOCAL_VARIABLE_AND_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableAndWriteNode\",\"location\":", 47); - - const pm_local_variable_and_write_node_t *cast = (const pm_local_variable_and_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the depth field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"depth\":", 8); - pm_buffer_append_format(buffer, "%" PRIu32, cast->depth); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableOperatorWriteNode\",\"location\":", 52); - - const pm_local_variable_operator_write_node_t *cast = (const pm_local_variable_operator_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the binary_operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22); - pm_dump_json_location(buffer, &cast->binary_operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the binary_operator field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"binary_operator\":", 18); - pm_dump_json_constant(buffer, parser, cast->binary_operator); - - // Dump the depth field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"depth\":", 8); - pm_buffer_append_format(buffer, "%" PRIu32, cast->depth); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_LOCAL_VARIABLE_OR_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableOrWriteNode\",\"location\":", 46); - - const pm_local_variable_or_write_node_t *cast = (const pm_local_variable_or_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the depth field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"depth\":", 8); - pm_buffer_append_format(buffer, "%" PRIu32, cast->depth); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_LOCAL_VARIABLE_READ_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableReadNode\",\"location\":", 43); - - const pm_local_variable_read_node_t *cast = (const pm_local_variable_read_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the depth field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"depth\":", 8); - pm_buffer_append_format(buffer, "%" PRIu32, cast->depth); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_LOCAL_VARIABLE_TARGET_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableTargetNode\",\"location\":", 45); - - const pm_local_variable_target_node_t *cast = (const pm_local_variable_target_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the depth field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"depth\":", 8); - pm_buffer_append_format(buffer, "%" PRIu32, cast->depth); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_LOCAL_VARIABLE_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableWriteNode\",\"location\":", 44); - - const pm_local_variable_write_node_t *cast = (const pm_local_variable_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the depth field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"depth\":", 8); - pm_buffer_append_format(buffer, "%" PRIu32, cast->depth); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_MATCH_LAST_LINE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"MatchLastLineNode\",\"location\":", 39); - - const pm_match_last_line_node_t *cast = (const pm_match_last_line_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the RegularExpressionFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"IGNORE_CASE\"", 13); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"EXTENDED\"", 10); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"MULTI_LINE\"", 12); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ONCE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ONCE\"", 6); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"EUC_JP\"", 8); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ASCII_8BIT\"", 12); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"WINDOWS_31J\"", 13); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"UTF_8\"", 7); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the content_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"content_loc\":", 14); - pm_dump_json_location(buffer, &cast->content_loc); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - // Dump the unescaped field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"unescaped\":", 12); - const pm_string_t *unescaped = &cast->unescaped; - pm_buffer_append_byte(buffer, '"'); - pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON); - pm_buffer_append_byte(buffer, '"'); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_MATCH_PREDICATE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"MatchPredicateNode\",\"location\":", 40); - - const pm_match_predicate_node_t *cast = (const pm_match_predicate_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the pattern field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"pattern\":", 10); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->pattern); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_MATCH_REQUIRED_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"MatchRequiredNode\",\"location\":", 39); - - const pm_match_required_node_t *cast = (const pm_match_required_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - // Dump the pattern field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"pattern\":", 10); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->pattern); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_MATCH_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"MatchWriteNode\",\"location\":", 36); - - const pm_match_write_node_t *cast = (const pm_match_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the call field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"call\":", 7); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->call); - - // Dump the targets field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"targets\":", 10); - const pm_node_list_t *targets = &cast->targets; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < targets->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, targets->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_MISSING_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"MissingNode\",\"location\":", 33); - - const pm_missing_node_t *cast = (const pm_missing_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_MODULE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ModuleNode\",\"location\":", 32); - - const pm_module_node_t *cast = (const pm_module_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the locals field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"locals\":", 9); - const pm_constant_id_list_t *locals = &cast->locals; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < locals->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json_constant(buffer, parser, locals->ids[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the module_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"module_keyword_loc\":", 21); - pm_dump_json_location(buffer, &cast->module_keyword_loc); - - // Dump the constant_path field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"constant_path\":", 16); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant_path); - - // Dump the body field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"body\":", 7); - if (cast->body != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->body); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the end_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); - pm_dump_json_location(buffer, &cast->end_keyword_loc); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_MULTI_TARGET_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"MultiTargetNode\",\"location\":", 37); - - const pm_multi_target_node_t *cast = (const pm_multi_target_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the lefts field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"lefts\":", 8); - const pm_node_list_t *lefts = &cast->lefts; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < lefts->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, lefts->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the rest field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rest\":", 7); - if (cast->rest != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the rights field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rights\":", 9); - const pm_node_list_t *rights = &cast->rights; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < rights->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, rights->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the lparen_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"lparen_loc\":", 13); - if (cast->lparen_loc.length != 0) { - pm_dump_json_location(buffer, &cast->lparen_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the rparen_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rparen_loc\":", 13); - if (cast->rparen_loc.length != 0) { - pm_dump_json_location(buffer, &cast->rparen_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_MULTI_WRITE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"MultiWriteNode\",\"location\":", 36); - - const pm_multi_write_node_t *cast = (const pm_multi_write_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the lefts field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"lefts\":", 8); - const pm_node_list_t *lefts = &cast->lefts; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < lefts->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, lefts->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the rest field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rest\":", 7); - if (cast->rest != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the rights field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rights\":", 9); - const pm_node_list_t *rights = &cast->rights; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < rights->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, rights->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the lparen_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"lparen_loc\":", 13); - if (cast->lparen_loc.length != 0) { - pm_dump_json_location(buffer, &cast->lparen_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the rparen_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rparen_loc\":", 13); - if (cast->rparen_loc.length != 0) { - pm_dump_json_location(buffer, &cast->rparen_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_NEXT_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"NextNode\",\"location\":", 30); - - const pm_next_node_t *cast = (const pm_next_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the arguments field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"arguments\":", 12); - if (cast->arguments != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_NIL_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"NilNode\",\"location\":", 29); - - const pm_nil_node_t *cast = (const pm_nil_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_NO_BLOCK_PARAMETER_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"NoBlockParameterNode\",\"location\":", 42); - - const pm_no_block_parameter_node_t *cast = (const pm_no_block_parameter_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_NO_KEYWORDS_PARAMETER_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"NoKeywordsParameterNode\",\"location\":", 45); - - const pm_no_keywords_parameter_node_t *cast = (const pm_no_keywords_parameter_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_NUMBERED_PARAMETERS_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"NumberedParametersNode\",\"location\":", 44); - - const pm_numbered_parameters_node_t *cast = (const pm_numbered_parameters_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the maximum field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"maximum\":", 10); - pm_buffer_append_format(buffer, "%" PRIu8, cast->maximum); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_NUMBERED_REFERENCE_READ_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"NumberedReferenceReadNode\",\"location\":", 47); - - const pm_numbered_reference_read_node_t *cast = (const pm_numbered_reference_read_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the number field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"number\":", 9); - pm_buffer_append_format(buffer, "%" PRIu32, cast->number); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_OPTIONAL_KEYWORD_PARAMETER_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"OptionalKeywordParameterNode\",\"location\":", 50); - - const pm_optional_keyword_parameter_node_t *cast = (const pm_optional_keyword_parameter_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the ParameterFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_OPTIONAL_PARAMETER_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"OptionalParameterNode\",\"location\":", 43); - - const pm_optional_parameter_node_t *cast = (const pm_optional_parameter_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the ParameterFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the value field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->value); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_OR_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"OrNode\",\"location\":", 28); - - const pm_or_node_t *cast = (const pm_or_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the left field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"left\":", 7); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->left); - - // Dump the right field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"right\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->right); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_PARAMETERS_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ParametersNode\",\"location\":", 36); - - const pm_parameters_node_t *cast = (const pm_parameters_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the requireds field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"requireds\":", 12); - const pm_node_list_t *requireds = &cast->requireds; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < requireds->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, requireds->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the optionals field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"optionals\":", 12); - const pm_node_list_t *optionals = &cast->optionals; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < optionals->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, optionals->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the rest field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rest\":", 7); - if (cast->rest != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the posts field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"posts\":", 8); - const pm_node_list_t *posts = &cast->posts; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < posts->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, posts->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the keywords field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keywords\":", 11); - const pm_node_list_t *keywords = &cast->keywords; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < keywords->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, keywords->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the keyword_rest field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_rest\":", 15); - if (cast->keyword_rest != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->keyword_rest); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the block field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"block\":", 8); - if (cast->block != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_PARENTHESES_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ParenthesesNode\",\"location\":", 37); - - const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the ParenthesesNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"MULTIPLE_STATEMENTS\"", 21); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the body field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"body\":", 7); - if (cast->body != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->body); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_PINNED_EXPRESSION_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"PinnedExpressionNode\",\"location\":", 42); - - const pm_pinned_expression_node_t *cast = (const pm_pinned_expression_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the expression field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"expression\":", 13); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the lparen_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"lparen_loc\":", 13); - pm_dump_json_location(buffer, &cast->lparen_loc); - - // Dump the rparen_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rparen_loc\":", 13); - pm_dump_json_location(buffer, &cast->rparen_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_PINNED_VARIABLE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"PinnedVariableNode\",\"location\":", 40); - - const pm_pinned_variable_node_t *cast = (const pm_pinned_variable_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the variable field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"variable\":", 11); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->variable); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_POST_EXECUTION_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"PostExecutionNode\",\"location\":", 39); - - const pm_post_execution_node_t *cast = (const pm_post_execution_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - if (cast->statements != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_PRE_EXECUTION_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"PreExecutionNode\",\"location\":", 38); - - const pm_pre_execution_node_t *cast = (const pm_pre_execution_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - if (cast->statements != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_PROGRAM_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ProgramNode\",\"location\":", 33); - - const pm_program_node_t *cast = (const pm_program_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the locals field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"locals\":", 9); - const pm_constant_id_list_t *locals = &cast->locals; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < locals->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json_constant(buffer, parser, locals->ids[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_RANGE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"RangeNode\",\"location\":", 31); - - const pm_range_node_t *cast = (const pm_range_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the RangeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"EXCLUDE_END\"", 13); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the left field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"left\":", 7); - if (cast->left != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->left); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the right field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"right\":", 8); - if (cast->right != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->right); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_RATIONAL_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"RationalNode\",\"location\":", 34); - - const pm_rational_node_t *cast = (const pm_rational_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the IntegerBaseFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_BINARY)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"BINARY\"", 8); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_DECIMAL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"DECIMAL\"", 9); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_OCTAL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"OCTAL\"", 7); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_HEXADECIMAL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"HEXADECIMAL\"", 13); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the numerator field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"numerator\":", 12); - pm_integer_string(buffer, &cast->numerator); - - // Dump the denominator field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"denominator\":", 14); - pm_integer_string(buffer, &cast->denominator); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_REDO_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"RedoNode\",\"location\":", 30); - - const pm_redo_node_t *cast = (const pm_redo_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_REGULAR_EXPRESSION_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"RegularExpressionNode\",\"location\":", 43); - - const pm_regular_expression_node_t *cast = (const pm_regular_expression_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the RegularExpressionFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"IGNORE_CASE\"", 13); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"EXTENDED\"", 10); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"MULTI_LINE\"", 12); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ONCE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ONCE\"", 6); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"EUC_JP\"", 8); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"ASCII_8BIT\"", 12); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"WINDOWS_31J\"", 13); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"UTF_8\"", 7); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the content_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"content_loc\":", 14); - pm_dump_json_location(buffer, &cast->content_loc); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - // Dump the unescaped field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"unescaped\":", 12); - const pm_string_t *unescaped = &cast->unescaped; - pm_buffer_append_byte(buffer, '"'); - pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON); - pm_buffer_append_byte(buffer, '"'); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_REQUIRED_KEYWORD_PARAMETER_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"RequiredKeywordParameterNode\",\"location\":", 50); - - const pm_required_keyword_parameter_node_t *cast = (const pm_required_keyword_parameter_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the ParameterFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - pm_dump_json_location(buffer, &cast->name_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_REQUIRED_PARAMETER_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"RequiredParameterNode\",\"location\":", 43); - - const pm_required_parameter_node_t *cast = (const pm_required_parameter_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the ParameterFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - pm_dump_json_constant(buffer, parser, cast->name); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_RESCUE_MODIFIER_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"RescueModifierNode\",\"location\":", 40); - - const pm_rescue_modifier_node_t *cast = (const pm_rescue_modifier_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the expression field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"expression\":", 13); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression); - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - // Dump the rescue_expression field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rescue_expression\":", 20); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->rescue_expression); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_RESCUE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"RescueNode\",\"location\":", 32); - - const pm_rescue_node_t *cast = (const pm_rescue_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - // Dump the exceptions field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"exceptions\":", 13); - const pm_node_list_t *exceptions = &cast->exceptions; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < exceptions->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, exceptions->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - if (cast->operator_loc.length != 0) { - pm_dump_json_location(buffer, &cast->operator_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the reference field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"reference\":", 12); - if (cast->reference != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->reference); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the then_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"then_keyword_loc\":", 19); - if (cast->then_keyword_loc.length != 0) { - pm_dump_json_location(buffer, &cast->then_keyword_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - if (cast->statements != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the subsequent field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"subsequent\":", 13); - if (cast->subsequent != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->subsequent); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_REST_PARAMETER_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"RestParameterNode\",\"location\":", 39); - - const pm_rest_parameter_node_t *cast = (const pm_rest_parameter_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the ParameterFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the name field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name\":", 7); - if (cast->name != PM_CONSTANT_ID_UNSET) { - pm_dump_json_constant(buffer, parser, cast->name); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the name_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"name_loc\":", 11); - if (cast->name_loc.length != 0) { - pm_dump_json_location(buffer, &cast->name_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_RETRY_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"RetryNode\",\"location\":", 31); - - const pm_retry_node_t *cast = (const pm_retry_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_RETURN_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ReturnNode\",\"location\":", 32); - - const pm_return_node_t *cast = (const pm_return_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - // Dump the arguments field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"arguments\":", 12); - if (cast->arguments != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_SELF_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"SelfNode\",\"location\":", 30); - - const pm_self_node_t *cast = (const pm_self_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_SHAREABLE_CONSTANT_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"ShareableConstantNode\",\"location\":", 43); - - const pm_shareable_constant_node_t *cast = (const pm_shareable_constant_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the ShareableConstantNodeFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"LITERAL\"", 9); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"EXPERIMENTAL_EVERYTHING\"", 25); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"EXPERIMENTAL_COPY\"", 19); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the write field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"write\":", 8); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->write); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_SINGLETON_CLASS_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"SingletonClassNode\",\"location\":", 40); - - const pm_singleton_class_node_t *cast = (const pm_singleton_class_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the locals field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"locals\":", 9); - const pm_constant_id_list_t *locals = &cast->locals; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < locals->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json_constant(buffer, parser, locals->ids[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the class_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"class_keyword_loc\":", 20); - pm_dump_json_location(buffer, &cast->class_keyword_loc); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the expression field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"expression\":", 13); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression); - - // Dump the body field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"body\":", 7); - if (cast->body != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->body); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the end_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); - pm_dump_json_location(buffer, &cast->end_keyword_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_SOURCE_ENCODING_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"SourceEncodingNode\",\"location\":", 40); - - const pm_source_encoding_node_t *cast = (const pm_source_encoding_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_SOURCE_FILE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"SourceFileNode\",\"location\":", 36); - - const pm_source_file_node_t *cast = (const pm_source_file_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the StringFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FORCED_UTF8_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FORCED_BINARY_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FROZEN)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FROZEN\"", 8); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_MUTABLE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"MUTABLE\"", 9); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the filepath field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"filepath\":", 11); - const pm_string_t *filepath = &cast->filepath; - pm_buffer_append_byte(buffer, '"'); - pm_buffer_append_source(buffer, pm_string_source(filepath), pm_string_length(filepath), PM_BUFFER_ESCAPING_JSON); - pm_buffer_append_byte(buffer, '"'); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_SOURCE_LINE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"SourceLineNode\",\"location\":", 36); - - const pm_source_line_node_t *cast = (const pm_source_line_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_SPLAT_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"SplatNode\",\"location\":", 31); - - const pm_splat_node_t *cast = (const pm_splat_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the operator_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"operator_loc\":", 15); - pm_dump_json_location(buffer, &cast->operator_loc); - - // Dump the expression field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"expression\":", 13); - if (cast->expression != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_STATEMENTS_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"StatementsNode\",\"location\":", 36); - - const pm_statements_node_t *cast = (const pm_statements_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the body field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"body\":", 7); - const pm_node_list_t *body = &cast->body; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < body->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, body->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_STRING_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"StringNode\",\"location\":", 32); - - const pm_string_node_t *cast = (const pm_string_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the StringFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FORCED_UTF8_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FORCED_BINARY_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FROZEN)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FROZEN\"", 8); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_MUTABLE)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"MUTABLE\"", 9); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - if (cast->opening_loc.length != 0) { - pm_dump_json_location(buffer, &cast->opening_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the content_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"content_loc\":", 14); - pm_dump_json_location(buffer, &cast->content_loc); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - if (cast->closing_loc.length != 0) { - pm_dump_json_location(buffer, &cast->closing_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the unescaped field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"unescaped\":", 12); - const pm_string_t *unescaped = &cast->unescaped; - pm_buffer_append_byte(buffer, '"'); - pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON); - pm_buffer_append_byte(buffer, '"'); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_SUPER_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"SuperNode\",\"location\":", 31); - - const pm_super_node_t *cast = (const pm_super_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - // Dump the lparen_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"lparen_loc\":", 13); - if (cast->lparen_loc.length != 0) { - pm_dump_json_location(buffer, &cast->lparen_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the arguments field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"arguments\":", 12); - if (cast->arguments != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the rparen_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rparen_loc\":", 13); - if (cast->rparen_loc.length != 0) { - pm_dump_json_location(buffer, &cast->rparen_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the block field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"block\":", 8); - if (cast->block != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->block); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_SYMBOL_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"SymbolNode\",\"location\":", 32); - - const pm_symbol_node_t *cast = (const pm_symbol_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the SymbolFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - if (cast->opening_loc.length != 0) { - pm_dump_json_location(buffer, &cast->opening_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the value_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"value_loc\":", 12); - if (cast->value_loc.length != 0) { - pm_dump_json_location(buffer, &cast->value_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - if (cast->closing_loc.length != 0) { - pm_dump_json_location(buffer, &cast->closing_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the unescaped field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"unescaped\":", 12); - const pm_string_t *unescaped = &cast->unescaped; - pm_buffer_append_byte(buffer, '"'); - pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON); - pm_buffer_append_byte(buffer, '"'); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_TRUE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"TrueNode\",\"location\":", 30); - - const pm_true_node_t *cast = (const pm_true_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_UNDEF_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"UndefNode\",\"location\":", 31); - - const pm_undef_node_t *cast = (const pm_undef_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the names field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"names\":", 8); - const pm_node_list_t *names = &cast->names; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < names->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, names->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_UNLESS_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"UnlessNode\",\"location\":", 32); - - const pm_unless_node_t *cast = (const pm_unless_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - // Dump the predicate field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"predicate\":", 12); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate); - - // Dump the then_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"then_keyword_loc\":", 19); - if (cast->then_keyword_loc.length != 0) { - pm_dump_json_location(buffer, &cast->then_keyword_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - if (cast->statements != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the else_clause field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"else_clause\":", 14); - if (cast->else_clause != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->else_clause); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the end_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18); - if (cast->end_keyword_loc.length != 0) { - pm_dump_json_location(buffer, &cast->end_keyword_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_UNTIL_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"UntilNode\",\"location\":", 31); - - const pm_until_node_t *cast = (const pm_until_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the LoopFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_LOOP_FLAGS_BEGIN_MODIFIER)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"BEGIN_MODIFIER\"", 16); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - // Dump the do_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"do_keyword_loc\":", 17); - if (cast->do_keyword_loc.length != 0) { - pm_dump_json_location(buffer, &cast->do_keyword_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - if (cast->closing_loc.length != 0) { - pm_dump_json_location(buffer, &cast->closing_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the predicate field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"predicate\":", 12); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate); - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - if (cast->statements != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_WHEN_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"WhenNode\",\"location\":", 30); - - const pm_when_node_t *cast = (const pm_when_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - // Dump the conditions field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"conditions\":", 13); - const pm_node_list_t *conditions = &cast->conditions; - pm_buffer_append_byte(buffer, '['); - - for (size_t index = 0; index < conditions->size; index++) { - if (index != 0) pm_buffer_append_byte(buffer, ','); - pm_dump_json(buffer, parser, conditions->nodes[index]); - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the then_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"then_keyword_loc\":", 19); - if (cast->then_keyword_loc.length != 0) { - pm_dump_json_location(buffer, &cast->then_keyword_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - if (cast->statements != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_WHILE_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"WhileNode\",\"location\":", 31); - - const pm_while_node_t *cast = (const pm_while_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the LoopFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_LOOP_FLAGS_BEGIN_MODIFIER)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"BEGIN_MODIFIER\"", 16); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - // Dump the do_keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"do_keyword_loc\":", 17); - if (cast->do_keyword_loc.length != 0) { - pm_dump_json_location(buffer, &cast->do_keyword_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - if (cast->closing_loc.length != 0) { - pm_dump_json_location(buffer, &cast->closing_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the predicate field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"predicate\":", 12); - pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate); - - // Dump the statements field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"statements\":", 13); - if (cast->statements != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_X_STRING_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"XStringNode\",\"location\":", 33); - - const pm_x_string_node_t *cast = (const pm_x_string_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the EncodingFlags field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"flags\":", 8); - size_t flags = 0; - pm_buffer_append_byte(buffer, '['); - if (PM_NODE_FLAG_P(cast, PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22); - flags++; - } - if (PM_NODE_FLAG_P(cast, PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING)) { - if (flags != 0) pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24); - flags++; - } - pm_buffer_append_byte(buffer, ']'); - - // Dump the opening_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"opening_loc\":", 14); - pm_dump_json_location(buffer, &cast->opening_loc); - - // Dump the content_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"content_loc\":", 14); - pm_dump_json_location(buffer, &cast->content_loc); - - // Dump the closing_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"closing_loc\":", 14); - pm_dump_json_location(buffer, &cast->closing_loc); - - // Dump the unescaped field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"unescaped\":", 12); - const pm_string_t *unescaped = &cast->unescaped; - pm_buffer_append_byte(buffer, '"'); - pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON); - pm_buffer_append_byte(buffer, '"'); - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_YIELD_NODE: { - pm_buffer_append_string(buffer, "{\"type\":\"YieldNode\",\"location\":", 31); - - const pm_yield_node_t *cast = (const pm_yield_node_t *) node; - pm_dump_json_location(buffer, &cast->base.location); - - // Dump the keyword_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"keyword_loc\":", 14); - pm_dump_json_location(buffer, &cast->keyword_loc); - - // Dump the lparen_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"lparen_loc\":", 13); - if (cast->lparen_loc.length != 0) { - pm_dump_json_location(buffer, &cast->lparen_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the arguments field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"arguments\":", 12); - if (cast->arguments != NULL) { - pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - // Dump the rparen_loc field - pm_buffer_append_byte(buffer, ','); - pm_buffer_append_string(buffer, "\"rparen_loc\":", 13); - if (cast->rparen_loc.length != 0) { - pm_dump_json_location(buffer, &cast->rparen_loc); - } else { - pm_buffer_append_string(buffer, "null", 4); - } - - pm_buffer_append_byte(buffer, '}'); - break; - } - case PM_SCOPE_NODE: - break; - } -} - -#endif From e10f2521a2a96420175d676be5d5d130beefe6c5 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Fri, 20 Mar 2026 11:56:59 -0400 Subject: [PATCH 16/21] [PRISM] Use a flat lookup table for locals instead of an st_table --- iseq.c | 88 +++++++++++++--------- prism_compile.c | 193 ++++++++++++++++++++---------------------------- prism_compile.h | 92 +++++++++++++++++++++-- vm_eval.c | 5 +- 4 files changed, 221 insertions(+), 157 deletions(-) diff --git a/iseq.c b/iseq.c index 9a0c66490d2221..6f87b2df3e085b 100644 --- a/iseq.c +++ b/iseq.c @@ -1096,41 +1096,15 @@ rb_iseq_new_with_opt(VALUE ast_value, VALUE name, VALUE path, VALUE realpath, return iseq_translate(iseq); } -struct pm_iseq_new_with_opt_data { - rb_iseq_t *iseq; - pm_scope_node_t *node; -}; - -VALUE -pm_iseq_new_with_opt_try(VALUE d) -{ - struct pm_iseq_new_with_opt_data *data = (struct pm_iseq_new_with_opt_data *)d; - - // This can compile child iseqs, which can raise syntax errors - pm_iseq_compile_node(data->iseq, data->node); - - // This raises an exception if there is a syntax error - finish_iseq_build(data->iseq); - - return Qundef; -} - /** - * This is a step in the prism compiler that is called once all of the various - * options have been established. It is called from one of the pm_iseq_new_* - * functions or from the RubyVM::InstructionSequence APIs. It is responsible for - * allocating the instruction sequence, calling into the compiler, and returning - * the built instruction sequence. - * - * Importantly, this is also the function where the compiler is re-entered to - * compile child instruction sequences. A child instruction sequence is always - * compiled using a scope node, which is why we cast it explicitly to that here - * in the parameters (as opposed to accepting a generic pm_node_t *). + * Core implementation for building a prism iseq. This does not use rb_protect, + * so any exceptions (e.g. from finish_iseq_build) propagate normally up the + * call stack — matching the parse.y compiler's behavior. */ rb_iseq_t * -pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, - int first_lineno, const rb_iseq_t *parent, int isolated_depth, - enum rb_iseq_type type, const rb_compile_option_t *option, int *error_state) +pm_iseq_build(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, + int first_lineno, const rb_iseq_t *parent, int isolated_depth, + enum rb_iseq_type type, const rb_compile_option_t *option) { rb_iseq_t *iseq = iseq_alloc(); ISEQ_BODY(iseq)->prism = true; @@ -1157,15 +1131,59 @@ pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpa prepare_iseq_build(iseq, name, path, realpath, first_lineno, &code_location, node->ast_node->node_id, parent, isolated_depth, type, node->script_lines == NULL ? Qnil : *node->script_lines, option); + pm_iseq_compile_node(iseq, node); + finish_iseq_build(iseq); + + return iseq_translate(iseq); +} + +struct pm_iseq_new_with_opt_data { + rb_iseq_t *iseq; + pm_scope_node_t *node; + VALUE name, path, realpath; + int first_lineno, isolated_depth; + const rb_iseq_t *parent; + enum rb_iseq_type type; + const rb_compile_option_t *option; +}; + +static VALUE +pm_iseq_new_with_opt_try(VALUE d) +{ + struct pm_iseq_new_with_opt_data *data = (struct pm_iseq_new_with_opt_data *)d; + data->iseq = pm_iseq_build(data->node, data->name, data->path, data->realpath, + data->first_lineno, data->parent, data->isolated_depth, + data->type, data->option); + return Qundef; +} + +/** + * This is a step in the prism compiler that is called once all of the various + * options have been established. It is called from one of the pm_iseq_new_* + * functions or from the RubyVM::InstructionSequence APIs. + * + * This function uses rb_protect to catch exceptions, storing the error state + * in the provided out parameter. This is only needed at top-level entry points + * where the caller wants to handle errors gracefully. Child iseqs compiled + * during the compilation process do NOT go through this function — they use + * pm_iseq_build directly, letting exceptions propagate naturally (matching + * the parse.y compiler's behavior). + */ +rb_iseq_t * +pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, + int first_lineno, const rb_iseq_t *parent, int isolated_depth, + enum rb_iseq_type type, const rb_compile_option_t *option, int *error_state) +{ struct pm_iseq_new_with_opt_data data = { - .iseq = iseq, - .node = node + .node = node, .name = name, .path = path, .realpath = realpath, + .first_lineno = first_lineno, .parent = parent, + .isolated_depth = isolated_depth, .type = type, .option = option }; rb_protect(pm_iseq_new_with_opt_try, (VALUE)&data, error_state); if (*error_state) return NULL; - return iseq_translate(iseq); + return data.iseq; } rb_iseq_t * diff --git a/prism_compile.c b/prism_compile.c index 66f7d6f2fa32f7..063febb193b5d3 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -142,6 +142,19 @@ pm_iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int node #define PM_COMPILE_NOT_POPPED(node) \ pm_compile_node(iseq, (node), ret, false, scope_node) +// Direct-indexed lookup table. -1 means "not present". +#define PM_INDEX_LOOKUP_TABLE_INIT { .values = NULL, .capacity = 0, .owned = false } + +static inline void +pm_index_lookup_table_init(pm_index_lookup_table_t *table, int constants_size, rb_iseq_t *iseq) +{ + int capacity = constants_size + PM_INDEX_LOOKUP_SPECIALS; + table->values = compile_data_alloc2_type(iseq, int, capacity); + memset(table->values, -1, capacity * sizeof(int)); + table->capacity = capacity; + table->owned = false; +} + /** * Cached line lookup that avoids repeated binary searches. Since the compiler * walks the AST roughly in source order, consecutive lookups tend to be for @@ -1311,14 +1324,15 @@ static pm_local_index_t pm_lookup_local_index(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, pm_constant_id_t constant_id, int start_depth) { pm_local_index_t lindex = { 0 }; - st_data_t local_index; + int local_index; int level; for (level = 0; level < start_depth; level++) { scope_node = scope_node->previous; } - while (!st_lookup(scope_node->index_lookup_table, constant_id, &local_index)) { + while (!pm_index_lookup_table_lookup(&scope_node->index_lookup_table, constant_id, &local_index)) + { level++; if (scope_node->previous) { @@ -1342,12 +1356,10 @@ pm_lookup_local_index(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, pm_con // We add a constants mapping on the scope_node which is a mapping from // these constant_id indexes to the CRuby IDs that they represent. // This helper method allows easy access to those IDs -static ID +static inline ID pm_constant_id_lookup(const pm_scope_node_t *scope_node, pm_constant_id_t constant_id) { - if (constant_id < 1 || constant_id > pm_parser_constants_size(scope_node->parser)) { - rb_bug("constant_id out of range: %u", (unsigned int)constant_id); - } + RUBY_ASSERT(constant_id >= 1 && constant_id <= pm_parser_constants_size(scope_node->parser)); return scope_node->constants[constant_id - 1]; } @@ -1356,18 +1368,11 @@ pm_new_child_iseq(rb_iseq_t *iseq, pm_scope_node_t *node, VALUE name, const rb_i { debugs("[new_child_iseq]> ---------------------------------------\n"); int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth; - int error_state; - rb_iseq_t *ret_iseq = pm_iseq_new_with_opt(node, name, + rb_iseq_t *ret_iseq = pm_iseq_build(node, name, rb_iseq_path(iseq), rb_iseq_realpath(iseq), line_no, parent, isolated_depth ? isolated_depth + 1 : 0, - type, ISEQ_COMPILE_DATA(iseq)->option, &error_state); - - if (error_state) { - pm_scope_node_destroy(node); - RUBY_ASSERT(ret_iseq == NULL); - rb_jump_tag(error_state); - } + type, ISEQ_COMPILE_DATA(iseq)->option); debugs("[new_child_iseq]< ---------------------------------------\n"); return ret_iseq; } @@ -3307,30 +3312,27 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t void pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_t *previous) { - // This is very important, otherwise the scope node could be seen as having - // certain flags set that _should not_ be set. - memset(scope, 0, sizeof(pm_scope_node_t)); + if (previous) { + // Copy inherited fields from the parent scope in one shot, then + // zero out the fields that are scope-specific. + *scope = *previous; + scope->locals = (pm_constant_id_list_t) { 0 }; + scope->parameters = NULL; + scope->body = NULL; + scope->local_table_for_iseq_size = 0; + scope->index_lookup_table = (pm_index_lookup_table_t) PM_INDEX_LOOKUP_TABLE_INIT; + scope->pre_execution_anchor = NULL; + } + else { + memset(scope, 0, sizeof(pm_scope_node_t)); + } scope->base.type = PM_SCOPE_NODE; scope->base.location.start = node->location.start; scope->base.location.length = node->location.length; - scope->previous = previous; scope->ast_node = (pm_node_t *) node; - if (previous) { - scope->parser = previous->parser; - scope->options = previous->options; - scope->line_offsets = previous->line_offsets; - scope->start_line = previous->start_line; - scope->encoding = previous->encoding; - scope->filepath_encoding = previous->filepath_encoding; - scope->constants = previous->constants; - scope->coverage_enabled = previous->coverage_enabled; - scope->script_lines = previous->script_lines; - scope->last_line = previous->last_line; - } - switch (PM_NODE_TYPE(node)) { case PM_BLOCK_NODE: { const pm_block_node_t *cast = (const pm_block_node_t *) node; @@ -3427,8 +3429,8 @@ pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_ void pm_scope_node_destroy(pm_scope_node_t *scope_node) { - if (scope_node->index_lookup_table) { - st_free_table(scope_node->index_lookup_table); + if (scope_node->index_lookup_table.owned) { + xfree(scope_node->index_lookup_table.values); } } @@ -3618,8 +3620,7 @@ pm_compile_builtin_mandatory_only_method(rb_iseq_t *iseq, pm_scope_node_t *scope pm_scope_node_t next_scope_node; pm_scope_node_init(&def.base, &next_scope_node, scope_node); - int error_state; - const rb_iseq_t *mandatory_only_iseq = pm_iseq_new_with_opt( + const rb_iseq_t *mandatory_only_iseq = pm_iseq_build( &next_scope_node, rb_iseq_base_label(iseq), rb_iseq_path(iseq), @@ -3628,16 +3629,10 @@ pm_compile_builtin_mandatory_only_method(rb_iseq_t *iseq, pm_scope_node_t *scope NULL, 0, ISEQ_TYPE_METHOD, - ISEQ_COMPILE_DATA(iseq)->option, - &error_state + ISEQ_COMPILE_DATA(iseq)->option ); RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq); - if (error_state) { - RUBY_ASSERT(ISEQ_BODY(iseq)->mandatory_only_iseq == NULL); - rb_jump_tag(error_state); - } - pm_scope_node_destroy(&next_scope_node); return COMPILE_OK; } @@ -4755,33 +4750,7 @@ pm_add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return, pm_sc PUSH_SEQ(ret, ensure); } -struct pm_local_table_insert_ctx { - pm_scope_node_t *scope_node; - rb_ast_id_table_t *local_table_for_iseq; - int local_index; -}; - -static int -pm_local_table_insert_func(st_data_t *key, st_data_t *value, st_data_t arg, int existing) -{ - if (!existing) { - pm_constant_id_t constant_id = (pm_constant_id_t) *key; - struct pm_local_table_insert_ctx * ctx = (struct pm_local_table_insert_ctx *) arg; - - pm_scope_node_t *scope_node = ctx->scope_node; - rb_ast_id_table_t *local_table_for_iseq = ctx->local_table_for_iseq; - int local_index = ctx->local_index; - ID local = pm_constant_id_lookup(scope_node, constant_id); - local_table_for_iseq->ids[local_index] = local; - - *value = (st_data_t)local_index; - - ctx->local_index++; - } - - return ST_CONTINUE; -} /** * Insert a local into the local table for the iseq. This is used to create the @@ -4789,24 +4758,23 @@ pm_local_table_insert_func(st_data_t *key, st_data_t *value, st_data_t arg, int * inserted are regular named locals, as opposed to special forwarding locals. */ static void -pm_insert_local_index(pm_constant_id_t constant_id, int local_index, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node) +pm_insert_local_index(pm_constant_id_t constant_id, int local_index, pm_index_lookup_table_t *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node) { RUBY_ASSERT((constant_id & PM_SPECIAL_CONSTANT_FLAG) == 0); ID local = pm_constant_id_lookup(scope_node, constant_id); local_table_for_iseq->ids[local_index] = local; - st_insert(index_lookup_table, (st_data_t) constant_id, (st_data_t) local_index); + pm_index_lookup_table_insert(index_lookup_table, constant_id, local_index); } /** - * Insert a local into the local table for the iseq that is a special forwarding - * local variable. + * Insert a special forwarding local (*, **, &, ...) into the local table. */ static void -pm_insert_local_special(ID local_name, int local_index, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq) +pm_insert_local_special(pm_constant_id_t special_id, ID local_name, int local_index, pm_index_lookup_table_t *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq) { local_table_for_iseq->ids[local_index] = local_name; - st_insert(index_lookup_table, (st_data_t) (local_name | PM_SPECIAL_CONSTANT_FLAG), (st_data_t) local_index); + pm_index_lookup_table_insert(index_lookup_table, special_id, local_index); } /** @@ -4816,7 +4784,7 @@ pm_insert_local_special(ID local_name, int local_index, st_table *index_lookup_t * local and index lookup tables and increments the local index as necessary. */ static int -pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node, int local_index) +pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, pm_index_lookup_table_t *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node, int local_index) { for (size_t index = 0; index < node->lefts.size; index++) { const pm_node_t *left = node->lefts.nodes[index]; @@ -6312,8 +6280,9 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod // hidden variables and multi target nodes size_t locals_size = locals->size; - // Index lookup table buffer size is only the number of the locals - st_table *index_lookup_table = st_init_numtable(); + // Index lookup table buffer size is only the number of the locals. + // We'll initialize it after computing table_size below. + pm_index_lookup_table_t index_lookup_table = PM_INDEX_LOOKUP_TABLE_INIT; int table_size = (int) locals_size; @@ -6437,6 +6406,10 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod rb_ast_id_table_t *local_table_for_iseq = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID)); local_table_for_iseq->size = table_size; + // Init the direct-indexed lookup table. The capacity is based on the + // parser's constant pool size (for regular locals) plus special slots. + pm_index_lookup_table_init(&index_lookup_table, (int) pm_parser_constants_size(scope_node->parser), iseq); + //********END OF STEP 1********** //********STEP 2********** @@ -6489,7 +6462,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod local_table_for_iseq->ids[local_index] = local; } else { - pm_insert_local_index(param->name, local_index, index_lookup_table, local_table_for_iseq, scope_node); + pm_insert_local_index(param->name, local_index, &index_lookup_table, local_table_for_iseq, scope_node); } break; @@ -6522,7 +6495,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod local_table_for_iseq->ids[local_index] = local; } else { - pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node); + pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node); } } } @@ -6548,14 +6521,14 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod local_table_for_iseq->ids[local_index] = local; } else { - pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node); + pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node); } } else { // def foo(a, (b, *c, d), e = 1, *, g, (h, *i, j), k:, l: 1, **m, &n) // ^ body->param.flags.anon_rest = true; - pm_insert_local_special(idMULT, local_index, index_lookup_table, local_table_for_iseq); + pm_insert_local_special(PM_CONSTANT_MULT, idMULT, local_index, &index_lookup_table, local_table_for_iseq); } local_index++; @@ -6595,7 +6568,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod local_table_for_iseq->ids[local_index] = local; } else { - pm_insert_local_index(param->name, local_index, index_lookup_table, local_table_for_iseq, scope_node); + pm_insert_local_index(param->name, local_index, &index_lookup_table, local_table_for_iseq, scope_node); } break; } @@ -6630,7 +6603,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod local_table_for_iseq->ids[local_index] = local; } else { - pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node); + pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node); } local_index++; } @@ -6660,7 +6633,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod local_table_for_iseq->ids[local_index] = local; } else { - pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node); + pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node); } local_index++; } @@ -6722,12 +6695,12 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod local_table_for_iseq->ids[local_index] = local; } else { - pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node); + pm_insert_local_index(constant_id, local_index, &index_lookup_table, local_table_for_iseq, scope_node); } } else { body->param.flags.anon_kwrest = true; - pm_insert_local_special(idPow, local_index, index_lookup_table, local_table_for_iseq); + pm_insert_local_special(PM_CONSTANT_POW, idPow, local_index, &index_lookup_table, local_table_for_iseq); } local_index++; @@ -6741,7 +6714,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod body->param.rest_start = local_index; body->param.flags.has_rest = true; body->param.flags.anon_rest = true; - pm_insert_local_special(idMULT, local_index++, index_lookup_table, local_table_for_iseq); + pm_insert_local_special(PM_CONSTANT_MULT, idMULT, local_index++, &index_lookup_table, local_table_for_iseq); // Add the anonymous ** RUBY_ASSERT(!body->param.flags.has_kw); @@ -6750,16 +6723,16 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod body->param.flags.anon_kwrest = true; body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1); keyword->rest_start = local_index; - pm_insert_local_special(idPow, local_index++, index_lookup_table, local_table_for_iseq); + pm_insert_local_special(PM_CONSTANT_POW, idPow, local_index++, &index_lookup_table, local_table_for_iseq); // Add the anonymous & body->param.block_start = local_index; body->param.flags.has_block = true; - pm_insert_local_special(idAnd, local_index++, index_lookup_table, local_table_for_iseq); + pm_insert_local_special(PM_CONSTANT_AND, idAnd, local_index++, &index_lookup_table, local_table_for_iseq); } // Add the ... - pm_insert_local_special(idDot3, local_index++, index_lookup_table, local_table_for_iseq); + pm_insert_local_special(PM_CONSTANT_DOT3, idDot3, local_index++, &index_lookup_table, local_table_for_iseq); break; } default: @@ -6785,11 +6758,11 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod local_table_for_iseq->ids[local_index] = local; } else { - pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node); + pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node); } } else { - pm_insert_local_special(idAnd, local_index, index_lookup_table, local_table_for_iseq); + pm_insert_local_special(PM_CONSTANT_AND, idAnd, local_index, &index_lookup_table, local_table_for_iseq); } local_index++; @@ -6825,7 +6798,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod const pm_node_t *required = requireds_list->nodes[i]; if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE)) { - local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) required, index_lookup_table, local_table_for_iseq, scope_node, local_index); + local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) required, &index_lookup_table, local_table_for_iseq, scope_node, local_index); } } } @@ -6839,7 +6812,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod const pm_node_t *post = posts_list->nodes[i]; if (PM_NODE_TYPE_P(post, PM_MULTI_TARGET_NODE)) { - local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) post, index_lookup_table, local_table_for_iseq, scope_node, local_index); + local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) post, &index_lookup_table, local_table_for_iseq, scope_node, local_index); } } } @@ -6867,7 +6840,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod const uint8_t param_name[] = { '_', '1' + i }; pm_constant_id_t constant_id = pm_parser_constant_find(scope_node->parser, param_name, 2); RUBY_ASSERT(constant_id && "parser should fill in any gaps in numbered parameters"); - pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node); + pm_insert_local_index(constant_id, local_index, &index_lookup_table, local_table_for_iseq, scope_node); } body->param.lead_num = maximum; body->param.flags.has_lead = true; @@ -6890,7 +6863,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod if (block_locals && block_locals->size) { for (size_t i = 0; i < block_locals->size; i++, local_index++) { pm_constant_id_t constant_id = ((const pm_block_local_variable_node_t *) block_locals->nodes[i])->name; - pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node); + pm_insert_local_index(constant_id, local_index, &index_lookup_table, local_table_for_iseq, scope_node); } } @@ -6899,14 +6872,13 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod for (size_t i = 0; i < scope_node->locals.size; i++) { pm_constant_id_t constant_id = locals->ids[i]; if (constant_id) { - struct pm_local_table_insert_ctx ctx; - ctx.scope_node = scope_node; - ctx.local_table_for_iseq = local_table_for_iseq; - ctx.local_index = local_index; - - st_update(index_lookup_table, (st_data_t)constant_id, pm_local_table_insert_func, (st_data_t)&ctx); - - local_index = ctx.local_index; + int existing; + if (!pm_index_lookup_table_lookup(&index_lookup_table, constant_id, &existing)) { + ID local = pm_constant_id_lookup(scope_node, constant_id); + local_table_for_iseq->ids[local_index] = local; + pm_index_lookup_table_insert(&index_lookup_table, constant_id, local_index); + local_index++; + } } } } @@ -6914,10 +6886,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod //********END OF STEP 4********** // We set the index_lookup_table on the scope node so we can - // refer to the parameters correctly - if (scope_node->index_lookup_table) { - st_free_table(scope_node->index_lookup_table); - } + // refer to the parameters correctly. scope_node->index_lookup_table = index_lookup_table; iseq_calc_param_size(iseq); @@ -11389,15 +11358,15 @@ pm_parse_process(pm_parse_result_t *result, pm_node_t *node, VALUE *script_lines scope_node->line_offsets = pm_parser_line_offsets(parser); scope_node->start_line = pm_parser_start_line(parser); size_t constants_size = pm_parser_constants_size(parser); - scope_node->constants = constants_size ? xcalloc(constants_size, sizeof(ID)) : NULL; + scope_node->constants = constants_size ? xmalloc(constants_size * sizeof(ID)) : NULL; pm_intern_constants_ctx_t intern_ctx = { .constants = scope_node->constants, .encoding = scope_node->encoding, .index = 0 }; pm_parser_constants_each(parser, pm_intern_constants_callback, &intern_ctx); - scope_node->index_lookup_table = st_init_numtable(); pm_constant_id_list_t *locals = &scope_node->locals; + pm_index_lookup_table_init_heap(&scope_node->index_lookup_table, (int) constants_size); for (size_t index = 0; index < locals->size; index++) { - st_insert(scope_node->index_lookup_table, locals->ids[index], index); + pm_index_lookup_table_insert(&scope_node->index_lookup_table, locals->ids[index], (int) index); } // If we got here, this is a success and we can return Qnil to indicate that diff --git a/prism_compile.h b/prism_compile.h index 09f611569db700..448579390259b6 100644 --- a/prism_compile.h +++ b/prism_compile.h @@ -16,6 +16,82 @@ typedef struct pm_local_index_struct { // A declaration for the struct that lives in compile.c. struct iseq_link_anchor; +/** + * A direct-indexed lookup table mapping constant IDs to local variable indices. + * Regular constant IDs (1..constants_size) index directly. Special forwarding + * parameter IDs (idMULT|FLAG, etc.) are mapped to 4 extra slots at the end. + * + * All lookups are O(1) — a single array dereference. + * The table is arena-allocated for child scopes (no explicit free needed). + */ +typedef struct { + /** Array of local indices, indexed by constant_id. -1 means not present. */ + int *values; + + /** Total number of slots (constants_size + PM_INDEX_LOOKUP_SPECIALS). */ + int capacity; + + /** Whether the values array is heap-allocated and needs explicit free. */ + bool owned; +} pm_index_lookup_table_t; + +/** Number of extra slots for special forwarding parameter IDs. */ +#define PM_INDEX_LOOKUP_SPECIALS 4 + +/** Slot offsets for special forwarding parameters (relative to constants_size). */ +#define PM_SPECIAL_CONSTANT_FLAG ((pm_constant_id_t) (1 << 31)) +#define PM_INDEX_LOOKUP_SPECIAL_MULT 0 +#define PM_INDEX_LOOKUP_SPECIAL_POW 1 +#define PM_INDEX_LOOKUP_SPECIAL_AND 2 +#define PM_INDEX_LOOKUP_SPECIAL_DOT3 3 + +/** + * Special constant IDs for forwarding parameters. These use bit 31 to + * distinguish them from regular prism constant pool IDs. The lower bits + * encode which special slot (0-3) they map to in the lookup table. + */ +#define PM_CONSTANT_MULT ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_MULT)) +#define PM_CONSTANT_POW ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_POW)) +#define PM_CONSTANT_AND ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_AND)) +#define PM_CONSTANT_DOT3 ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_DOT3)) + +static inline int +pm_index_lookup_table_index(const pm_index_lookup_table_t *table, pm_constant_id_t key) +{ + if (LIKELY(!(key & PM_SPECIAL_CONSTANT_FLAG))) { + return (int) key - 1; + } + return table->capacity - PM_INDEX_LOOKUP_SPECIALS + (int)(key & ~PM_SPECIAL_CONSTANT_FLAG); +} + +static inline void +pm_index_lookup_table_insert(pm_index_lookup_table_t *table, pm_constant_id_t key, int value) +{ + int idx = pm_index_lookup_table_index(table, key); + RUBY_ASSERT(idx >= 0 && idx < table->capacity); + table->values[idx] = value; +} + +static inline int +pm_index_lookup_table_lookup(const pm_index_lookup_table_t *table, pm_constant_id_t key, int *value) +{ + int idx = pm_index_lookup_table_index(table, key); + RUBY_ASSERT(idx >= 0 && idx < table->capacity); + if (table->values[idx] == -1) return 0; + *value = table->values[idx]; + return 1; +} + +static inline void +pm_index_lookup_table_init_heap(pm_index_lookup_table_t *table, int constants_size) +{ + int cap = constants_size + PM_INDEX_LOOKUP_SPECIALS; + table->values = (int *) ruby_xmalloc(cap * sizeof(int)); + memset(table->values, -1, cap * sizeof(int)); + table->capacity = cap; + table->owned = true; +} + // ScopeNodes are helper nodes, and will never be part of the AST. We manually // declare them here to avoid generating them. typedef struct pm_scope_node { @@ -54,7 +130,14 @@ typedef struct pm_scope_node { int local_table_for_iseq_size; ID *constants; - st_table *index_lookup_table; + + /** + * A flat lookup table mapping constant IDs (or special IDs) to local + * variable indices. When allocated from the compile data arena (child + * scopes), no explicit free is needed. When heap-allocated (top-level + * scope in pm_parse_process), owned is set to true so destroy can free it. + */ + pm_index_lookup_table_t index_lookup_table; // The current coverage setting, passed down through the various scopes. int coverage_enabled; @@ -96,12 +179,6 @@ typedef struct { bool parsed; } pm_parse_result_t; -#define PM_SPECIAL_CONSTANT_FLAG ((pm_constant_id_t)(1 << 31)) -#define PM_CONSTANT_AND ((pm_constant_id_t)(idAnd | PM_SPECIAL_CONSTANT_FLAG)) -#define PM_CONSTANT_DOT3 ((pm_constant_id_t)(idDot3 | PM_SPECIAL_CONSTANT_FLAG)) -#define PM_CONSTANT_MULT ((pm_constant_id_t)(idMULT | PM_SPECIAL_CONSTANT_FLAG)) -#define PM_CONSTANT_POW ((pm_constant_id_t)(idPow | PM_SPECIAL_CONSTANT_FLAG)) - void pm_parse_result_init(pm_parse_result_t *result); VALUE pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error); VALUE pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines); @@ -116,5 +193,6 @@ rb_iseq_t *pm_iseq_new_top(pm_scope_node_t *node, VALUE name, VALUE path, VALUE rb_iseq_t *pm_iseq_new_main(pm_scope_node_t *node, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt, int *error_state); rb_iseq_t *pm_iseq_new_eval(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth, int *error_state); rb_iseq_t *pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth, enum rb_iseq_type, const rb_compile_option_t *option, int *error_state); +rb_iseq_t *pm_iseq_build(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth, enum rb_iseq_type, const rb_compile_option_t *option); VALUE pm_iseq_compile_node(rb_iseq_t *iseq, pm_scope_node_t *node); diff --git a/vm_eval.c b/vm_eval.c index 4216ec56f33291..25d366f5cd19e6 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -1840,9 +1840,8 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line, const pm_options_scope_t *options_scope = pm_options_scope(result.options, scopes_count - scopes_index - 1); parent_scope->coverage_enabled = coverage_enabled; parent_scope->parser = result.parser; - parent_scope->index_lookup_table = st_init_numtable(); - int locals_count = ISEQ_BODY(iseq)->local_table_size; + pm_index_lookup_table_init_heap(&parent_scope->index_lookup_table, (int) pm_parser_constants_size(result.parser)); parent_scope->local_table_for_iseq_size = locals_count; pm_constant_id_list_init(&parent_scope->locals); @@ -1877,7 +1876,7 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line, constant_id = pm_parser_constant_find(result.parser, source, length); } - st_insert(parent_scope->index_lookup_table, (st_data_t) constant_id, (st_data_t) local_index); + pm_index_lookup_table_insert(&parent_scope->index_lookup_table, constant_id, local_index); } pm_constant_id_list_append(result.arena, &parent_scope->locals, constant_id); From 7bb8f3d77c4bc131ece899690e61cd78435e5824 Mon Sep 17 00:00:00 2001 From: BurdetteLamar Date: Tue, 17 Mar 2026 00:29:20 +0100 Subject: [PATCH 17/21] [DOC] Fix links in extension.rdoc --- doc/extension.rdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/extension.rdoc b/doc/extension.rdoc index 18dc5817d45830..4be150c9f5d7c8 100644 --- a/doc/extension.rdoc +++ b/doc/extension.rdoc @@ -317,11 +317,11 @@ rb_ary_aref(int argc, const VALUE *argv, VALUE ary) :: rb_ary_entry(VALUE ary, long offset) :: - \ary[offset] + ary\[offset] rb_ary_store(VALUE ary, long offset, VALUE obj) :: - \ary[offset] = obj + ary\[offset] = obj rb_ary_subseq(VALUE ary, long beg, long len) :: From ffd69d025a5a32aeb4e9a2e0fa5fe4c82dc79842 Mon Sep 17 00:00:00 2001 From: BurdetteLamar Date: Tue, 17 Mar 2026 19:29:47 +0100 Subject: [PATCH 18/21] [DOC] Doc for Pathname#== --- pathname_builtin.rb | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pathname_builtin.rb b/pathname_builtin.rb index 3a676680c27db9..c92737ebce5a49 100644 --- a/pathname_builtin.rb +++ b/pathname_builtin.rb @@ -236,10 +236,18 @@ def freeze self end + # call-seq: + # self == other -> true or false + # + # Returns whether the stored paths in +self+ and +other+ are equal: + # + # pn = Pathname.new('lib') + # pn == Pathname.new('lib') # => true + # pn == Pathname.new('./lib') # => false # - # Compare this pathname with +other+. The comparison is string-based. - # Be aware that two different paths (foo.txt and ./foo.txt) - # can refer to the same file. + # Returns +false+ if +other+ is not a pathname: + # + # pn == 'lib' # => false # def ==(other) return false unless Pathname === other From 7397bbf74489d8767bda3727ef1f08b85b6ef52e Mon Sep 17 00:00:00 2001 From: BurdetteLamar Date: Tue, 17 Mar 2026 20:08:14 +0100 Subject: [PATCH 19/21] [DOC] Doc for Pathname#== --- pathname_builtin.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pathname_builtin.rb b/pathname_builtin.rb index c92737ebce5a49..87bf926cca6eb9 100644 --- a/pathname_builtin.rb +++ b/pathname_builtin.rb @@ -246,7 +246,7 @@ def freeze # pn == Pathname.new('./lib') # => false # # Returns +false+ if +other+ is not a pathname: - # + # # pn == 'lib' # => false # def ==(other) From 8c53dd3e0fc0e4854ed713a74d39c5d816ba9554 Mon Sep 17 00:00:00 2001 From: BurdetteLamar Date: Tue, 17 Mar 2026 20:24:18 +0100 Subject: [PATCH 20/21] [DOC] Doc for pathname#absolute? --- pathname_builtin.rb | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/pathname_builtin.rb b/pathname_builtin.rb index 87bf926cca6eb9..d69707e34a7dd3 100644 --- a/pathname_builtin.rb +++ b/pathname_builtin.rb @@ -636,17 +636,19 @@ def root? chop_basename(@path) == nil && SEPARATOR_PAT.match?(@path) end - # Predicate method for testing whether a path is absolute. + # call-seq: + # absolute? -> true or false # - # It returns +true+ if the pathname begins with a slash. + # Returns whether +self+ contains an absolute path: # - # p = Pathname.new('/im/sure') - # p.absolute? - # #=> true + # Pathname.new('/home').absolute? # => true + # Pathname.new('lib').absolute? # => false + # + # OS-dependent for some paths: + # + # Pathname.new('C:/').absolute? # => true # On Windows. + # Pathname.new('C:/').absolute? # => false # Elsewhere. # - # p = Pathname.new('not/so/sure') - # p.absolute? - # #=> false def absolute? ABSOLUTE_PATH.match? @path end From 4860f350180815769eab20bc35b4151ff90c968f Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Fri, 20 Mar 2026 20:38:02 -0400 Subject: [PATCH 21/21] [ruby/prism] Clean up types on node find https://github.com/ruby/prism/commit/6f597d3ff7 --- lib/prism/node_find.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/prism/node_find.rb b/lib/prism/node_find.rb index 46dd598c054530..697ee430e8b90e 100644 --- a/lib/prism/node_find.rb +++ b/lib/prism/node_find.rb @@ -15,7 +15,6 @@ module NodeFind # :nodoc: # Find the node for the given callable or backtrace location. #-- #: (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable, bool rubyvm) -> Node? - #++ def self.find(callable, rubyvm) case callable when Proc @@ -50,7 +49,6 @@ class Find # Parse the given file path, returning a ParseResult or nil. #-- #: (String? file) -> ParseResult? - def parse_file(file) return unless file && File.readable?(file) result = Prism.parse_file(file) @@ -64,7 +62,6 @@ class RubyVMCallableFind < Find # Find the node for the given callable using the ISeq node_id. #-- #: (Method | UnboundMethod | Proc callable) -> Node? - def find(callable) return unless (source_location = callable.source_location) return unless (result = parse_file(source_location[0])) @@ -83,7 +80,6 @@ class RubyVMBacktraceLocationFind < Find # Find the node for the given backtrace location using node_id. #-- #: (Thread::Backtrace::Location location) -> Node? - def find(location) file = location.absolute_path || location.path return unless (result = parse_file(file)) @@ -101,7 +97,6 @@ class LineMethodFind < Find # Find the node for the given method by matching on name and line. #-- #: (Method | UnboundMethod callable) -> Node? - def find(callable) return unless (source_location = callable.source_location) return unless (result = parse_file(source_location[0])) @@ -128,7 +123,6 @@ class LineLambdaFind < Find # Find the node for the given lambda by matching on line. #-- #: (Proc callable) -> Node? - def find(callable) return unless (source_location = callable.source_location) return unless (result = parse_file(source_location[0])) @@ -154,7 +148,6 @@ class LineProcFind < Find # Find the node for the given proc by matching on line. #-- #: (Proc callable) -> Node? - def find(callable) return unless (source_location = callable.source_location) return unless (result = parse_file(source_location[0])) @@ -180,7 +173,6 @@ class LineBacktraceLocationFind < Find # Find the node for the given backtrace location by matching on line. #-- #: (Thread::Backtrace::Location location) -> Node? - def find(location) file = location.absolute_path || location.path return unless (result = parse_file(file))