rubyduino 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (735) hide show
  1. checksums.yaml +7 -0
  2. data/.gitmodules +3 -0
  3. data/CHANGELOG.md +9 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +72 -0
  6. data/Rakefile +12 -0
  7. data/bin/rubyduino +186 -0
  8. data/examples/hello.rb +9 -0
  9. data/lib/rubyduino/arduino_entry.c +9 -0
  10. data/lib/rubyduino/sp_runtime.h +159 -0
  11. data/lib/rubyduino/spinel.rb +8 -0
  12. data/lib/rubyduino/spinel_arduino_codegen.rb +129 -0
  13. data/lib/rubyduino/version.rb +5 -0
  14. data/lib/rubyduino.rb +9 -0
  15. data/sig/rubyduino.rbs +4 -0
  16. data/vendor/spinel/AUTHORS +1 -0
  17. data/vendor/spinel/LICENSE +19 -0
  18. data/vendor/spinel/Makefile +406 -0
  19. data/vendor/spinel/POLY-AS-SET.md +217 -0
  20. data/vendor/spinel/README.md +409 -0
  21. data/vendor/spinel/benchmark/bm_ackermann.rb +12 -0
  22. data/vendor/spinel/benchmark/bm_ao_render.rb +323 -0
  23. data/vendor/spinel/benchmark/bm_attr_accessor.rb +41 -0
  24. data/vendor/spinel/benchmark/bm_bigint_fib.rb +10 -0
  25. data/vendor/spinel/benchmark/bm_binary_trees.rb +53 -0
  26. data/vendor/spinel/benchmark/bm_csv_process.rb +58 -0
  27. data/vendor/spinel/benchmark/bm_fannkuch.rb +88 -0
  28. data/vendor/spinel/benchmark/bm_fasta.rb +87 -0
  29. data/vendor/spinel/benchmark/bm_fib.rb +9 -0
  30. data/vendor/spinel/benchmark/bm_gcbench.rb +73 -0
  31. data/vendor/spinel/benchmark/bm_getivar.rb +34 -0
  32. data/vendor/spinel/benchmark/bm_getivar_module.rb +34 -0
  33. data/vendor/spinel/benchmark/bm_huffman.rb +141 -0
  34. data/vendor/spinel/benchmark/bm_inline.rb +68 -0
  35. data/vendor/spinel/benchmark/bm_io_wordcount.rb +57 -0
  36. data/vendor/spinel/benchmark/bm_json_parse.rb +157 -0
  37. data/vendor/spinel/benchmark/bm_keyword_args.rb +23 -0
  38. data/vendor/spinel/benchmark/bm_life.rb +70 -0
  39. data/vendor/spinel/benchmark/bm_linked_list.rb +75 -0
  40. data/vendor/spinel/benchmark/bm_loops_times.rb +16 -0
  41. data/vendor/spinel/benchmark/bm_mandel_term.rb +34 -0
  42. data/vendor/spinel/benchmark/bm_matmul.rb +42 -0
  43. data/vendor/spinel/benchmark/bm_nbody.rb +115 -0
  44. data/vendor/spinel/benchmark/bm_nested_loop.rb +29 -0
  45. data/vendor/spinel/benchmark/bm_nqueens.rb +46 -0
  46. data/vendor/spinel/benchmark/bm_object_new.rb +21 -0
  47. data/vendor/spinel/benchmark/bm_object_new_init.rb +21 -0
  48. data/vendor/spinel/benchmark/bm_object_new_no_escape.rb +28 -0
  49. data/vendor/spinel/benchmark/bm_partial_sums.rb +38 -0
  50. data/vendor/spinel/benchmark/bm_pidigits.rb +31 -0
  51. data/vendor/spinel/benchmark/bm_rbtree.rb +100 -0
  52. data/vendor/spinel/benchmark/bm_ruby_xor.rb +28 -0
  53. data/vendor/spinel/benchmark/bm_send_bmethod.rb +31 -0
  54. data/vendor/spinel/benchmark/bm_send_cfunc_block.rb +18 -0
  55. data/vendor/spinel/benchmark/bm_send_rubyfunc_block.rb +23 -0
  56. data/vendor/spinel/benchmark/bm_setivar.rb +33 -0
  57. data/vendor/spinel/benchmark/bm_setivar_object.rb +33 -0
  58. data/vendor/spinel/benchmark/bm_setivar_young.rb +37 -0
  59. data/vendor/spinel/benchmark/bm_sieve.rb +23 -0
  60. data/vendor/spinel/benchmark/bm_so_lists.rb +47 -0
  61. data/vendor/spinel/benchmark/bm_so_mandelbrot.rb +65 -0
  62. data/vendor/spinel/benchmark/bm_spectral_norm.rb +71 -0
  63. data/vendor/spinel/benchmark/bm_splay.rb +128 -0
  64. data/vendor/spinel/benchmark/bm_str_concat.rb +15 -0
  65. data/vendor/spinel/benchmark/bm_structaref.rb +25 -0
  66. data/vendor/spinel/benchmark/bm_structaset.rb +24 -0
  67. data/vendor/spinel/benchmark/bm_sudoku.rb +217 -0
  68. data/vendor/spinel/benchmark/bm_tak.rb +10 -0
  69. data/vendor/spinel/benchmark/bm_tarai.rb +10 -0
  70. data/vendor/spinel/benchmark/bm_template.rb +50 -0
  71. data/vendor/spinel/benchmark/bm_throw.rb +25 -0
  72. data/vendor/spinel/benchmark/bm_wordfreq.rb +43 -0
  73. data/vendor/spinel/docs/FFI.md +198 -0
  74. data/vendor/spinel/examples/ffi/libm/README.md +24 -0
  75. data/vendor/spinel/examples/ffi/libm/libm.rb +17 -0
  76. data/vendor/spinel/examples/ffi/sqlite/README.md +73 -0
  77. data/vendor/spinel/examples/ffi/sqlite/blog.rb +185 -0
  78. data/vendor/spinel/examples/ffi/sqlite/sqlite3_lib.rb +46 -0
  79. data/vendor/spinel/lib/erb.rb +19 -0
  80. data/vendor/spinel/lib/forwardable.rb +8 -0
  81. data/vendor/spinel/lib/mruby_shim.h +118 -0
  82. data/vendor/spinel/lib/optparse.rb +123 -0
  83. data/vendor/spinel/lib/regexp/re_compile.c +979 -0
  84. data/vendor/spinel/lib/regexp/re_exec.c +665 -0
  85. data/vendor/spinel/lib/regexp/re_internal.h +146 -0
  86. data/vendor/spinel/lib/regexp/re_utf8.c +76 -0
  87. data/vendor/spinel/lib/set.rb +12 -0
  88. data/vendor/spinel/lib/sp_bigint.c +5400 -0
  89. data/vendor/spinel/lib/sp_bigint.h +117 -0
  90. data/vendor/spinel/lib/sp_runtime.h +1361 -0
  91. data/vendor/spinel/lib/stringio.c +286 -0
  92. data/vendor/spinel/lib/stringio.rb +5 -0
  93. data/vendor/spinel/lib/strscan.c +170 -0
  94. data/vendor/spinel/lib/strscan.rb +55 -0
  95. data/vendor/spinel/spinel +191 -0
  96. data/vendor/spinel/spinel.bat +158 -0
  97. data/vendor/spinel/spinel_codegen.rb +39906 -0
  98. data/vendor/spinel/spinel_parse +0 -0
  99. data/vendor/spinel/spinel_parse.c +1586 -0
  100. data/vendor/spinel/test/alias_global.rb +16 -0
  101. data/vendor/spinel/test/alias_global.rb.expected +3 -0
  102. data/vendor/spinel/test/alias_method.rb +28 -0
  103. data/vendor/spinel/test/alias_method.rb.expected +5 -0
  104. data/vendor/spinel/test/and_node_poly_operand.rb +24 -0
  105. data/vendor/spinel/test/anon_block_forward.rb +47 -0
  106. data/vendor/spinel/test/anon_block_forward.rb.expected +4 -0
  107. data/vendor/spinel/test/array_3d_nested.rb +48 -0
  108. data/vendor/spinel/test/array_clear_typed.rb +40 -0
  109. data/vendor/spinel/test/array_clear_typed.rb.expected +7 -0
  110. data/vendor/spinel/test/array_concat.rb +18 -0
  111. data/vendor/spinel/test/array_concat.rb.expected +2 -0
  112. data/vendor/spinel/test/array_each_with_object.rb +17 -0
  113. data/vendor/spinel/test/array_each_with_object.rb.expected +2 -0
  114. data/vendor/spinel/test/array_fill_poly.rb +17 -0
  115. data/vendor/spinel/test/array_flat_map.rb +16 -0
  116. data/vendor/spinel/test/array_flat_map.rb.expected +2 -0
  117. data/vendor/spinel/test/array_keyed_hash_int_array_eql.rb +29 -0
  118. data/vendor/spinel/test/array_keyed_hash_int_array_eql.rb.expected +6 -0
  119. data/vendor/spinel/test/array_method_name_clash.rb +15 -0
  120. data/vendor/spinel/test/array_method_name_clash.rb.expected +1 -0
  121. data/vendor/spinel/test/array_new_block_typed_container.rb +37 -0
  122. data/vendor/spinel/test/array_new_block_typed_container.rb.expected +7 -0
  123. data/vendor/spinel/test/array_new_empty_inner_deferred.rb +47 -0
  124. data/vendor/spinel/test/array_new_empty_inner_deferred.rb.expected +8 -0
  125. data/vendor/spinel/test/array_partition_gc.rb +20 -0
  126. data/vendor/spinel/test/array_partition_gc.rb.expected +3 -0
  127. data/vendor/spinel/test/array_plus.rb +18 -0
  128. data/vendor/spinel/test/array_plus.rb.expected +2 -0
  129. data/vendor/spinel/test/array_rotate_bang.rb +54 -0
  130. data/vendor/spinel/test/array_rotate_bang.rb.expected +34 -0
  131. data/vendor/spinel/test/array_shuffle_ptr.rb +11 -0
  132. data/vendor/spinel/test/array_shuffle_ptr.rb.expected +1 -0
  133. data/vendor/spinel/test/array_slice_bang.rb +81 -0
  134. data/vendor/spinel/test/array_slice_bang.rb.expected +40 -0
  135. data/vendor/spinel/test/attr.rb +77 -0
  136. data/vendor/spinel/test/attr.rb.expected +9 -0
  137. data/vendor/spinel/test/attr_writer_poly_box.rb +24 -0
  138. data/vendor/spinel/test/attr_writer_poly_no_double_eval.rb +29 -0
  139. data/vendor/spinel/test/attr_writer_poly_no_double_eval.rb.expected +3 -0
  140. data/vendor/spinel/test/attr_writer_returns_rhs.rb +23 -0
  141. data/vendor/spinel/test/auto_unbox_keeps_int_slot.rb +38 -0
  142. data/vendor/spinel/test/auto_unbox_keeps_int_slot.rb.expected +3 -0
  143. data/vendor/spinel/test/auto_unbox_poly_to_int_local.rb +36 -0
  144. data/vendor/spinel/test/auto_unbox_poly_to_int_local.rb.expected +2 -0
  145. data/vendor/spinel/test/back_ref.rb +21 -0
  146. data/vendor/spinel/test/back_ref.rb.expected +6 -0
  147. data/vendor/spinel/test/bare_return_in_cls_method.rb +46 -0
  148. data/vendor/spinel/test/bare_return_in_cls_method.rb.expected +2 -0
  149. data/vendor/spinel/test/bare_return_in_initialize.rb +55 -0
  150. data/vendor/spinel/test/bare_return_in_initialize.rb.expected +4 -0
  151. data/vendor/spinel/test/bare_return_in_poly_method.rb +26 -0
  152. data/vendor/spinel/test/bare_return_in_poly_method.rb.expected +2 -0
  153. data/vendor/spinel/test/bigint_div_by_zero.rb +43 -0
  154. data/vendor/spinel/test/bigint_div_by_zero.rb.expected +3 -0
  155. data/vendor/spinel/test/block2.rb +31 -0
  156. data/vendor/spinel/test/block2.rb.expected +4 -0
  157. data/vendor/spinel/test/block_forward_block_arg.rb +60 -0
  158. data/vendor/spinel/test/block_forward_block_arg.rb.expected +4 -0
  159. data/vendor/spinel/test/block_forward_recv_typed.rb +82 -0
  160. data/vendor/spinel/test/block_forward_recv_typed.rb.expected +11 -0
  161. data/vendor/spinel/test/block_forward_self_call.rb +61 -0
  162. data/vendor/spinel/test/block_forward_self_call.rb.expected +6 -0
  163. data/vendor/spinel/test/block_given_block_param.rb +46 -0
  164. data/vendor/spinel/test/block_given_block_param.rb.expected +3 -0
  165. data/vendor/spinel/test/block_param_shadow.rb +246 -0
  166. data/vendor/spinel/test/block_param_shadow.rb.expected +71 -0
  167. data/vendor/spinel/test/bm_instance_eval.rb +209 -0
  168. data/vendor/spinel/test/bm_instance_eval.rb.expected +27 -0
  169. data/vendor/spinel/test/bound_method_array.rb +22 -0
  170. data/vendor/spinel/test/bound_method_array.rb.expected +4 -0
  171. data/vendor/spinel/test/bound_method_basic.rb +27 -0
  172. data/vendor/spinel/test/bound_method_basic.rb.expected +2 -0
  173. data/vendor/spinel/test/bound_method_gc.rb +30 -0
  174. data/vendor/spinel/test/bound_method_gc.rb.expected +1 -0
  175. data/vendor/spinel/test/bound_method_obj_recv.rb +41 -0
  176. data/vendor/spinel/test/bound_method_obj_recv.rb.expected +4 -0
  177. data/vendor/spinel/test/bound_method_single_eval.rb +37 -0
  178. data/vendor/spinel/test/bound_method_single_eval.rb.expected +4 -0
  179. data/vendor/spinel/test/box_pointer_to_poly.rb +27 -0
  180. data/vendor/spinel/test/box_pointer_to_poly.rb.expected +1 -0
  181. data/vendor/spinel/test/box_unbox_local_assign_cond.rb +22 -0
  182. data/vendor/spinel/test/box_unbox_local_assign_cond.rb.expected +2 -0
  183. data/vendor/spinel/test/bundle_array_a.rb +400 -0
  184. data/vendor/spinel/test/bundle_array_a.rb.expected +117 -0
  185. data/vendor/spinel/test/bundle_array_b.rb +369 -0
  186. data/vendor/spinel/test/bundle_array_b.rb.expected +136 -0
  187. data/vendor/spinel/test/bundle_array_c.rb +146 -0
  188. data/vendor/spinel/test/bundle_array_c.rb.expected +51 -0
  189. data/vendor/spinel/test/bundle_array_d.rb +181 -0
  190. data/vendor/spinel/test/bundle_array_d.rb.expected +66 -0
  191. data/vendor/spinel/test/bundle_hash.rb +328 -0
  192. data/vendor/spinel/test/bundle_hash.rb.expected +104 -0
  193. data/vendor/spinel/test/bundle_int_array.rb +125 -0
  194. data/vendor/spinel/test/bundle_int_array.rb.expected +24 -0
  195. data/vendor/spinel/test/bundle_integer.rb +248 -0
  196. data/vendor/spinel/test/bundle_integer.rb.expected +113 -0
  197. data/vendor/spinel/test/bundle_io_sys.rb +223 -0
  198. data/vendor/spinel/test/bundle_io_sys.rb.expected +62 -0
  199. data/vendor/spinel/test/bundle_misc_a.rb +462 -0
  200. data/vendor/spinel/test/bundle_misc_a.rb.expected +208 -0
  201. data/vendor/spinel/test/bundle_misc_b.rb +401 -0
  202. data/vendor/spinel/test/bundle_misc_b.rb.expected +120 -0
  203. data/vendor/spinel/test/bundle_poly.rb +145 -0
  204. data/vendor/spinel/test/bundle_poly.rb.expected +66 -0
  205. data/vendor/spinel/test/bundle_string_a.rb +278 -0
  206. data/vendor/spinel/test/bundle_string_a.rb.expected +93 -0
  207. data/vendor/spinel/test/bundle_string_b.rb +226 -0
  208. data/vendor/spinel/test/bundle_string_b.rb.expected +83 -0
  209. data/vendor/spinel/test/bundle_sym.rb +302 -0
  210. data/vendor/spinel/test/bundle_sym.rb.expected +117 -0
  211. data/vendor/spinel/test/call_and_write.rb +28 -0
  212. data/vendor/spinel/test/call_and_write.rb.expected +3 -0
  213. data/vendor/spinel/test/call_arg_int_to_obj_cast.rb +55 -0
  214. data/vendor/spinel/test/call_arg_int_to_obj_cast.rb.expected +1 -0
  215. data/vendor/spinel/test/call_op_write.rb +51 -0
  216. data/vendor/spinel/test/call_op_write.rb.expected +11 -0
  217. data/vendor/spinel/test/call_or_write.rb +35 -0
  218. data/vendor/spinel/test/call_or_write.rb.expected +3 -0
  219. data/vendor/spinel/test/case.rb +43 -0
  220. data/vendor/spinel/test/case.rb.expected +10 -0
  221. data/vendor/spinel/test/case_string_when_sym_no_match.rb +59 -0
  222. data/vendor/spinel/test/case_string_when_sym_no_match.rb.expected +7 -0
  223. data/vendor/spinel/test/case_when_class.rb +70 -0
  224. data/vendor/spinel/test/case_when_class.rb.expected +5 -0
  225. data/vendor/spinel/test/chained_attr_setter.rb +55 -0
  226. data/vendor/spinel/test/chained_ivar_op_assign_emits_inner_write.rb +28 -0
  227. data/vendor/spinel/test/chained_ivar_op_assign_emits_inner_write.rb.expected +3 -0
  228. data/vendor/spinel/test/chained_ivar_write_call_rhs.rb +30 -0
  229. data/vendor/spinel/test/chained_ivar_write_call_rhs.rb.expected +2 -0
  230. data/vendor/spinel/test/chained_ivar_write_split.rb +26 -0
  231. data/vendor/spinel/test/chained_ivar_write_split.rb.expected +3 -0
  232. data/vendor/spinel/test/chained_ivar_write_subclass.rb +26 -0
  233. data/vendor/spinel/test/chained_ivar_write_subclass.rb.expected +2 -0
  234. data/vendor/spinel/test/chained_or_assign_collection_array_nested.rb +32 -0
  235. data/vendor/spinel/test/chained_or_assign_collection_array_nested.rb.expected +3 -0
  236. data/vendor/spinel/test/chained_or_assign_collection_element.rb +29 -0
  237. data/vendor/spinel/test/chained_or_assign_collection_element.rb.expected +2 -0
  238. data/vendor/spinel/test/chained_or_assign_collection_poly_array.rb +25 -0
  239. data/vendor/spinel/test/chained_or_assign_collection_poly_array.rb.expected +3 -0
  240. data/vendor/spinel/test/chained_or_assign_collection_str_keys.rb +24 -0
  241. data/vendor/spinel/test/chained_or_assign_collection_str_keys.rb.expected +3 -0
  242. data/vendor/spinel/test/class_constant_path_read.rb +26 -0
  243. data/vendor/spinel/test/class_constant_path_read.rb.expected +4 -0
  244. data/vendor/spinel/test/class_constant_sym_array.rb +19 -0
  245. data/vendor/spinel/test/class_constant_sym_array.rb.expected +4 -0
  246. data/vendor/spinel/test/class_def_order.rb +66 -0
  247. data/vendor/spinel/test/class_def_order.rb.expected +4 -0
  248. data/vendor/spinel/test/class_method_open_class_call.rb +31 -0
  249. data/vendor/spinel/test/class_method_open_class_call.rb.expected +3 -0
  250. data/vendor/spinel/test/class_var_read.rb +113 -0
  251. data/vendor/spinel/test/class_var_read.rb.expected +8 -0
  252. data/vendor/spinel/test/class_var_write.rb +19 -0
  253. data/vendor/spinel/test/class_var_write.rb.expected +1 -0
  254. data/vendor/spinel/test/cls_ivar_type_parent_defer.rb +32 -0
  255. data/vendor/spinel/test/cls_method_object.rb +31 -0
  256. data/vendor/spinel/test/cls_method_object.rb.expected +2 -0
  257. data/vendor/spinel/test/codegen_class_in_module_with_explicit_parent.rb +15 -0
  258. data/vendor/spinel/test/codegen_class_in_module_with_explicit_parent.rb.expected +1 -0
  259. data/vendor/spinel/test/codegen_const_lookup_in_toplevel_method.rb +13 -0
  260. data/vendor/spinel/test/codegen_const_lookup_in_toplevel_method.rb.expected +1 -0
  261. data/vendor/spinel/test/comparable.rb +21 -0
  262. data/vendor/spinel/test/comparable.rb.expected +5 -0
  263. data/vendor/spinel/test/const_init_block_param_scan.rb +13 -0
  264. data/vendor/spinel/test/const_init_block_param_scan.rb.expected +2 -0
  265. data/vendor/spinel/test/constant_path.rb +102 -0
  266. data/vendor/spinel/test/constant_path.rb.expected +21 -0
  267. data/vendor/spinel/test/constants.rb +44 -0
  268. data/vendor/spinel/test/constants.rb.expected +13 -0
  269. data/vendor/spinel/test/control.rb +23 -0
  270. data/vendor/spinel/test/control.rb.expected +7 -0
  271. data/vendor/spinel/test/default_args.rb +108 -0
  272. data/vendor/spinel/test/default_args.rb.expected +13 -0
  273. data/vendor/spinel/test/default_argv_narrows_from_string_call_site.rb +32 -0
  274. data/vendor/spinel/test/default_argv_narrows_from_string_call_site.rb.expected +1 -0
  275. data/vendor/spinel/test/each_poly_recv_block_auto_splat.rb +43 -0
  276. data/vendor/spinel/test/each_poly_recv_block_auto_splat.rb.expected +2 -0
  277. data/vendor/spinel/test/each_with_object_seed_shadow.rb +14 -0
  278. data/vendor/spinel/test/each_with_object_seed_shadow.rb.expected +4 -0
  279. data/vendor/spinel/test/elsif_isa_chain.rb +56 -0
  280. data/vendor/spinel/test/elsif_isa_chain.rb.expected +6 -0
  281. data/vendor/spinel/test/embedded_var.rb +17 -0
  282. data/vendor/spinel/test/embedded_var.rb.expected +2 -0
  283. data/vendor/spinel/test/empty_array_param.rb +94 -0
  284. data/vendor/spinel/test/empty_array_param.rb.expected +18 -0
  285. data/vendor/spinel/test/empty_hash_ivar_string_value.rb +51 -0
  286. data/vendor/spinel/test/empty_hash_ivar_string_value.rb.expected +4 -0
  287. data/vendor/spinel/test/endless_method.rb +61 -0
  288. data/vendor/spinel/test/endless_method.rb.expected +11 -0
  289. data/vendor/spinel/test/endless_method_rescue.rb +33 -0
  290. data/vendor/spinel/test/endless_method_rescue.rb.expected +10 -0
  291. data/vendor/spinel/test/ensure_raise_overrides_body_raise.rb +19 -0
  292. data/vendor/spinel/test/ensure_raise_overrides_body_raise.rb.expected +1 -0
  293. data/vendor/spinel/test/ensure_runs_on_raise.rb +32 -0
  294. data/vendor/spinel/test/ensure_runs_on_raise.rb.expected +3 -0
  295. data/vendor/spinel/test/ensure_runs_on_raise_nested.rb +38 -0
  296. data/vendor/spinel/test/ensure_runs_on_raise_nested.rb.expected +4 -0
  297. data/vendor/spinel/test/ensure_runs_on_return.rb +61 -0
  298. data/vendor/spinel/test/ensure_runs_on_return.rb.expected +6 -0
  299. data/vendor/spinel/test/ensure_runs_on_return_from_rescue.rb +26 -0
  300. data/vendor/spinel/test/ensure_runs_on_return_from_rescue.rb.expected +2 -0
  301. data/vendor/spinel/test/ensure_runs_on_return_nested.rb +37 -0
  302. data/vendor/spinel/test/ensure_runs_on_return_nested.rb.expected +3 -0
  303. data/vendor/spinel/test/enumerable.rb +19 -0
  304. data/vendor/spinel/test/enumerable.rb.expected +2 -0
  305. data/vendor/spinel/test/env_string_inference.rb +37 -0
  306. data/vendor/spinel/test/env_string_inference.rb.expected +6 -0
  307. data/vendor/spinel/test/exception_object_methods.rb +99 -0
  308. data/vendor/spinel/test/exception_object_methods.rb.expected +15 -0
  309. data/vendor/spinel/test/exceptions.rb +34 -0
  310. data/vendor/spinel/test/exceptions.rb.expected +4 -0
  311. data/vendor/spinel/test/features.rb +32 -0
  312. data/vendor/spinel/test/features.rb.expected +9 -0
  313. data/vendor/spinel/test/ffi_buffer_reader.rb +23 -0
  314. data/vendor/spinel/test/ffi_buffer_reader.rb.expected +5 -0
  315. data/vendor/spinel/test/ffi_const.rb +12 -0
  316. data/vendor/spinel/test/ffi_const.rb.expected +5 -0
  317. data/vendor/spinel/test/ffi_libc_libm_basic.rb +16 -0
  318. data/vendor/spinel/test/ffi_libc_libm_basic.rb.expected +5 -0
  319. data/vendor/spinel/test/ffi_ptr_nil.rb +27 -0
  320. data/vendor/spinel/test/ffi_ptr_nil.rb.expected +2 -0
  321. data/vendor/spinel/test/ffi_void_return.rb +14 -0
  322. data/vendor/spinel/test/ffi_void_return.rb.expected +2 -0
  323. data/vendor/spinel/test/fiber_ivar_persists_across_yield.rb +22 -0
  324. data/vendor/spinel/test/fiber_ivar_persists_across_yield.rb.expected +3 -0
  325. data/vendor/spinel/test/fiber_yield_across_method_call.rb +28 -0
  326. data/vendor/spinel/test/fiber_yield_across_method_call.rb.expected +3 -0
  327. data/vendor/spinel/test/file_basename_gc.rb +59 -0
  328. data/vendor/spinel/test/file_basename_gc.rb.expected +2 -0
  329. data/vendor/spinel/test/forward_call_class_method_inherited_init.rb +36 -0
  330. data/vendor/spinel/test/forward_call_class_method_inherited_init.rb.expected +1 -0
  331. data/vendor/spinel/test/forward_call_class_method_inherited_init_int_array.rb +32 -0
  332. data/vendor/spinel/test/forward_call_class_method_inherited_init_int_array.rb.expected +1 -0
  333. data/vendor/spinel/test/forward_call_class_method_inherited_init_obj.rb +41 -0
  334. data/vendor/spinel/test/forward_call_class_method_inherited_init_obj.rb.expected +1 -0
  335. data/vendor/spinel/test/forward_call_class_method_int_array.rb +26 -0
  336. data/vendor/spinel/test/forward_call_class_method_int_array.rb.expected +1 -0
  337. data/vendor/spinel/test/forward_call_class_method_nested.rb +35 -0
  338. data/vendor/spinel/test/forward_call_class_method_nested.rb.expected +1 -0
  339. data/vendor/spinel/test/forward_call_class_method_obj.rb +36 -0
  340. data/vendor/spinel/test/forward_call_class_method_obj.rb.expected +1 -0
  341. data/vendor/spinel/test/forward_call_param_type_inference.rb +23 -0
  342. data/vendor/spinel/test/forward_call_param_type_inference.rb.expected +1 -0
  343. data/vendor/spinel/test/forward_call_param_type_int_array.rb +34 -0
  344. data/vendor/spinel/test/forward_call_param_type_int_array.rb.expected +1 -0
  345. data/vendor/spinel/test/forward_call_param_type_obj.rb +38 -0
  346. data/vendor/spinel/test/forward_call_param_type_obj.rb.expected +1 -0
  347. data/vendor/spinel/test/gc_root_ptr_array_literal.rb +63 -0
  348. data/vendor/spinel/test/gc_root_ptr_array_literal.rb.expected +1 -0
  349. data/vendor/spinel/test/gc_save_double_in_new.rb +13 -0
  350. data/vendor/spinel/test/gc_save_double_in_new.rb.expected +1 -0
  351. data/vendor/spinel/test/gc_scan_skip_inherited_ivar.rb +54 -0
  352. data/vendor/spinel/test/gc_scan_skip_inherited_ivar.rb.expected +2 -0
  353. data/vendor/spinel/test/global_var.rb +53 -0
  354. data/vendor/spinel/test/global_var.rb.expected +12 -0
  355. data/vendor/spinel/test/gvar.rb +22 -0
  356. data/vendor/spinel/test/gvar.rb.expected +4 -0
  357. data/vendor/spinel/test/hash_dig.rb +92 -0
  358. data/vendor/spinel/test/hash_dig.rb.expected +37 -0
  359. data/vendor/spinel/test/hash_keys_each_shadow.rb +40 -0
  360. data/vendor/spinel/test/hash_keys_each_shadow.rb.expected +9 -0
  361. data/vendor/spinel/test/hash_shorthand.rb +37 -0
  362. data/vendor/spinel/test/hash_shorthand.rb.expected +6 -0
  363. data/vendor/spinel/test/hash_shorthand_str.rb +48 -0
  364. data/vendor/spinel/test/hash_shorthand_str.rb.expected +19 -0
  365. data/vendor/spinel/test/heterogeneous_dispatch_int_return_narrow.rb +46 -0
  366. data/vendor/spinel/test/heterogeneous_dispatch_int_return_narrow.rb.expected +2 -0
  367. data/vendor/spinel/test/if_static_false_skips_dead_branch_compile.rb +50 -0
  368. data/vendor/spinel/test/if_static_false_skips_dead_branch_compile.rb.expected +3 -0
  369. data/vendor/spinel/test/implicit_self_param_poly.rb +17 -0
  370. data/vendor/spinel/test/implicit_self_param_poly.rb.expected +1 -0
  371. data/vendor/spinel/test/index_write.rb +106 -0
  372. data/vendor/spinel/test/index_write.rb.expected +30 -0
  373. data/vendor/spinel/test/inference_method_set.rb +35 -0
  374. data/vendor/spinel/test/inference_method_set.rb.expected +2 -0
  375. data/vendor/spinel/test/inherit.rb +52 -0
  376. data/vendor/spinel/test/inherit.rb.expected +7 -0
  377. data/vendor/spinel/test/inherited_method_param_widen.rb +49 -0
  378. data/vendor/spinel/test/inherited_method_param_widen.rb.expected +1 -0
  379. data/vendor/spinel/test/init_locals.rb +43 -0
  380. data/vendor/spinel/test/init_locals.rb.expected +3 -0
  381. data/vendor/spinel/test/initialize_param_poly_call_sites.rb +20 -0
  382. data/vendor/spinel/test/initialize_param_poly_call_sites.rb.expected +2 -0
  383. data/vendor/spinel/test/initialize_param_through_call.rb +15 -0
  384. data/vendor/spinel/test/initialize_param_through_call.rb.expected +1 -0
  385. data/vendor/spinel/test/initialize_void_wrapper_gc_save.rb +40 -0
  386. data/vendor/spinel/test/initialize_void_wrapper_gc_save.rb.expected +1 -0
  387. data/vendor/spinel/test/inspect.rb +86 -0
  388. data/vendor/spinel/test/inspect.rb.expected +52 -0
  389. data/vendor/spinel/test/instance_eval_trampoline.rb +88 -0
  390. data/vendor/spinel/test/instance_eval_trampoline.rb.expected +5 -0
  391. data/vendor/spinel/test/int_bracket_skip_sym_idx.rb +40 -0
  392. data/vendor/spinel/test/int_bracket_skip_sym_idx.rb.expected +5 -0
  393. data/vendor/spinel/test/int_keyed_hash_lookup_as_array.rb +19 -0
  394. data/vendor/spinel/test/int_keyed_hash_lookup_as_array.rb.expected +2 -0
  395. data/vendor/spinel/test/intarray_slice_assign_from_intarray_ptr_array_first.rb +25 -0
  396. data/vendor/spinel/test/intarray_slice_assign_from_intarray_ptr_array_first.rb.expected +1 -0
  397. data/vendor/spinel/test/integer_div.rb +21 -0
  398. data/vendor/spinel/test/integer_div.rb.expected +10 -0
  399. data/vendor/spinel/test/integer_div_by_zero.rb +80 -0
  400. data/vendor/spinel/test/integer_div_by_zero.rb.expected +10 -0
  401. data/vendor/spinel/test/interp_method_widening.rb +39 -0
  402. data/vendor/spinel/test/interp_method_widening.rb.expected +4 -0
  403. data/vendor/spinel/test/interp_symbol.rb +18 -0
  404. data/vendor/spinel/test/interp_symbol.rb.expected +3 -0
  405. data/vendor/spinel/test/introspect.rb +35 -0
  406. data/vendor/spinel/test/introspect.rb.expected +11 -0
  407. data/vendor/spinel/test/issue176_empty_hash_default.rb +34 -0
  408. data/vendor/spinel/test/issue176_empty_hash_default.rb.expected +3 -0
  409. data/vendor/spinel/test/issue203_string_new.rb +27 -0
  410. data/vendor/spinel/test/issue203_string_new.rb.expected +4 -0
  411. data/vendor/spinel/test/issue204_user_find_fetch.rb +25 -0
  412. data/vendor/spinel/test/issue204_user_find_fetch.rb.expected +5 -0
  413. data/vendor/spinel/test/issue207_factory_pattern.rb +35 -0
  414. data/vendor/spinel/test/issue207_factory_pattern.rb.expected +1 -0
  415. data/vendor/spinel/test/issue207_full_repro.rb +52 -0
  416. data/vendor/spinel/test/issue207_full_repro.rb.expected +1 -0
  417. data/vendor/spinel/test/issue208_inherited_class_method.rb +24 -0
  418. data/vendor/spinel/test/issue208_inherited_class_method.rb.expected +4 -0
  419. data/vendor/spinel/test/issue219_aref_chain.rb +36 -0
  420. data/vendor/spinel/test/issue219_aref_chain.rb.expected +5 -0
  421. data/vendor/spinel/test/issue224_bare_new_inherited.rb +66 -0
  422. data/vendor/spinel/test/issue224_bare_new_inherited.rb.expected +4 -0
  423. data/vendor/spinel/test/issue229_uncalled_cls_method.rb +76 -0
  424. data/vendor/spinel/test/issue229_uncalled_cls_method.rb.expected +3 -0
  425. data/vendor/spinel/test/issue235_chain_tail_widening.rb +48 -0
  426. data/vendor/spinel/test/issue235_chain_tail_widening.rb.expected +5 -0
  427. data/vendor/spinel/test/issue236_chain_empty_literal.rb +84 -0
  428. data/vendor/spinel/test/issue236_chain_empty_literal.rb.expected +7 -0
  429. data/vendor/spinel/test/issue239_cls_method_default_args.rb +41 -0
  430. data/vendor/spinel/test/issue239_cls_method_default_args.rb.expected +5 -0
  431. data/vendor/spinel/test/issue_266_def_length_inference.rb +63 -0
  432. data/vendor/spinel/test/issue_266_def_length_inference.rb.expected +1 -0
  433. data/vendor/spinel/test/ivar_and_write_basic.rb +34 -0
  434. data/vendor/spinel/test/ivar_and_write_basic.rb.expected +5 -0
  435. data/vendor/spinel/test/ivar_c_keyword.rb +14 -0
  436. data/vendor/spinel/test/ivar_c_keyword.rb.expected +1 -0
  437. data/vendor/spinel/test/ivar_float_array.rb +59 -0
  438. data/vendor/spinel/test/ivar_float_array.rb.expected +11 -0
  439. data/vendor/spinel/test/ivar_op_assign_bitwise_and_shift.rb +22 -0
  440. data/vendor/spinel/test/ivar_op_assign_bitwise_and_shift.rb.expected +6 -0
  441. data/vendor/spinel/test/ivar_or_write_basic.rb +57 -0
  442. data/vendor/spinel/test/ivar_or_write_basic.rb.expected +9 -0
  443. data/vendor/spinel/test/ivar_polymorphic.rb +87 -0
  444. data/vendor/spinel/test/ivar_polymorphic.rb.expected +12 -0
  445. data/vendor/spinel/test/ivar_ternary_mixed.rb +108 -0
  446. data/vendor/spinel/test/ivar_ternary_mixed.rb.expected +15 -0
  447. data/vendor/spinel/test/ivar_writer_heterogeneity.rb +34 -0
  448. data/vendor/spinel/test/ivar_writer_heterogeneity.rb.expected +2 -0
  449. data/vendor/spinel/test/known_constants.rb +25 -0
  450. data/vendor/spinel/test/known_constants.rb.expected +4 -0
  451. data/vendor/spinel/test/kw_nil_default_string_call.rb +6 -0
  452. data/vendor/spinel/test/kw_nil_default_string_call.rb.expected +2 -0
  453. data/vendor/spinel/test/kwargs.rb +21 -0
  454. data/vendor/spinel/test/kwargs.rb.expected +6 -0
  455. data/vendor/spinel/test/kwargs_param.rb +26 -0
  456. data/vendor/spinel/test/kwargs_param.rb.expected +2 -0
  457. data/vendor/spinel/test/kwargs_param_widen.rb +73 -0
  458. data/vendor/spinel/test/kwargs_param_widen.rb.expected +3 -0
  459. data/vendor/spinel/test/lrama_features.rb +142 -0
  460. data/vendor/spinel/test/lrama_features.rb.expected +38 -0
  461. data/vendor/spinel/test/map_array_block_result.rb +29 -0
  462. data/vendor/spinel/test/map_array_block_result.rb.expected +2 -0
  463. data/vendor/spinel/test/map_block_returns_nested_array.rb +53 -0
  464. data/vendor/spinel/test/map_empty_block.rb +26 -0
  465. data/vendor/spinel/test/map_empty_block.rb.expected +6 -0
  466. data/vendor/spinel/test/map_range_recv_array_block.rb +31 -0
  467. data/vendor/spinel/test/mega.rb +35 -0
  468. data/vendor/spinel/test/mega.rb.expected +7 -0
  469. data/vendor/spinel/test/method.rb +21 -0
  470. data/vendor/spinel/test/method.rb.expected +6 -0
  471. data/vendor/spinel/test/method_defined.rb +36 -0
  472. data/vendor/spinel/test/method_defined.rb.expected +17 -0
  473. data/vendor/spinel/test/method_dispatch_poly_array.rb +35 -0
  474. data/vendor/spinel/test/method_dispatch_poly_array.rb.expected +2 -0
  475. data/vendor/spinel/test/method_introspection.rb +24 -0
  476. data/vendor/spinel/test/method_introspection.rb.expected +6 -0
  477. data/vendor/spinel/test/method_param_unify_to_poly.rb +40 -0
  478. data/vendor/spinel/test/method_param_unify_to_poly.rb.expected +2 -0
  479. data/vendor/spinel/test/misc.rb +49 -0
  480. data/vendor/spinel/test/misc.rb.expected +7 -0
  481. data/vendor/spinel/test/mixin.rb +54 -0
  482. data/vendor/spinel/test/mixin.rb.expected +4 -0
  483. data/vendor/spinel/test/module_acc_dispatch_param_box.rb +46 -0
  484. data/vendor/spinel/test/module_acc_dispatch_param_box.rb.expected +2 -0
  485. data/vendor/spinel/test/module_class_new.rb +17 -0
  486. data/vendor/spinel/test/module_class_new.rb.expected +3 -0
  487. data/vendor/spinel/test/module_cls_method_string_return.rb +53 -0
  488. data/vendor/spinel/test/module_cls_method_string_return.rb.expected +5 -0
  489. data/vendor/spinel/test/module_const_array_widen.rb +36 -0
  490. data/vendor/spinel/test/module_const_array_widen.rb.expected +1 -0
  491. data/vendor/spinel/test/module_dispatch_param_widen.rb +55 -0
  492. data/vendor/spinel/test/module_dispatch_param_widen.rb.expected +1 -0
  493. data/vendor/spinel/test/module_function_namespace.rb +58 -0
  494. data/vendor/spinel/test/module_ivar_hash.rb +61 -0
  495. data/vendor/spinel/test/module_ivar_hash.rb.expected +7 -0
  496. data/vendor/spinel/test/module_relative_constant_path.rb +26 -0
  497. data/vendor/spinel/test/module_relative_constant_path.rb.expected +2 -0
  498. data/vendor/spinel/test/module_singleton_accessor.rb +65 -0
  499. data/vendor/spinel/test/module_singleton_accessor.rb.expected +3 -0
  500. data/vendor/spinel/test/module_singleton_accessor_poly.rb +62 -0
  501. data/vendor/spinel/test/module_singleton_accessor_poly.rb.expected +7 -0
  502. data/vendor/spinel/test/multi_arg_block_call.rb +56 -0
  503. data/vendor/spinel/test/multi_arg_block_call.rb.expected +5 -0
  504. data/vendor/spinel/test/multi_arg_yield.rb +70 -0
  505. data/vendor/spinel/test/multi_arg_yield.rb.expected +6 -0
  506. data/vendor/spinel/test/multi_assign_ivar.rb +33 -0
  507. data/vendor/spinel/test/multi_assign_ivar.rb.expected +1 -0
  508. data/vendor/spinel/test/multi_return.rb +35 -0
  509. data/vendor/spinel/test/multi_return.rb.expected +10 -0
  510. data/vendor/spinel/test/multi_return_bare.rb +77 -0
  511. data/vendor/spinel/test/multi_return_bare.rb.expected +16 -0
  512. data/vendor/spinel/test/multi_write_const.rb +36 -0
  513. data/vendor/spinel/test/multi_write_const.rb.expected +9 -0
  514. data/vendor/spinel/test/multi_write_from_poly_recv.rb +34 -0
  515. data/vendor/spinel/test/multi_write_from_poly_recv.rb.expected +1 -0
  516. data/vendor/spinel/test/multi_write_ivar.rb +34 -0
  517. data/vendor/spinel/test/multi_write_ivar.rb.expected +3 -0
  518. data/vendor/spinel/test/multi_write_ivar_const_from_array_rhs.rb +53 -0
  519. data/vendor/spinel/test/multi_write_ivar_const_from_array_rhs.rb.expected +6 -0
  520. data/vendor/spinel/test/multi_write_ivar_widening.rb +10 -0
  521. data/vendor/spinel/test/multi_write_ivar_widening.rb.expected +2 -0
  522. data/vendor/spinel/test/multi_write_map_block.rb +31 -0
  523. data/vendor/spinel/test/multi_write_map_block.rb.expected +7 -0
  524. data/vendor/spinel/test/multi_write_setter.rb +28 -0
  525. data/vendor/spinel/test/multi_write_setter.rb.expected +3 -0
  526. data/vendor/spinel/test/multi_write_typed_array_dispatch.rb +44 -0
  527. data/vendor/spinel/test/multi_write_typed_array_dispatch.rb.expected +3 -0
  528. data/vendor/spinel/test/nested_class_in_class.rb +38 -0
  529. data/vendor/spinel/test/nested_class_in_class.rb.expected +3 -0
  530. data/vendor/spinel/test/nested_class_module_const_resolution.rb +38 -0
  531. data/vendor/spinel/test/nested_class_module_const_resolution.rb.expected +2 -0
  532. data/vendor/spinel/test/nil_ivar.rb +44 -0
  533. data/vendor/spinel/test/nil_ivar.rb.expected +5 -0
  534. data/vendor/spinel/test/no_attr_write_shortcut_complex.rb +33 -0
  535. data/vendor/spinel/test/no_attr_write_shortcut_complex.rb.expected +3 -0
  536. data/vendor/spinel/test/no_attr_write_shortcut_multi.rb +38 -0
  537. data/vendor/spinel/test/no_attr_write_shortcut_multi.rb.expected +4 -0
  538. data/vendor/spinel/test/no_keywords_param.rb +15 -0
  539. data/vendor/spinel/test/no_keywords_param.rb.expected +2 -0
  540. data/vendor/spinel/test/nullable.rb +26 -0
  541. data/vendor/spinel/test/nullable.rb.expected +2 -0
  542. data/vendor/spinel/test/obj_array.rb +26 -0
  543. data/vendor/spinel/test/obj_array.rb.expected +6 -0
  544. data/vendor/spinel/test/object_new_sentinel.rb +18 -0
  545. data/vendor/spinel/test/object_new_sentinel.rb.expected +3 -0
  546. data/vendor/spinel/test/object_truthy.rb +31 -0
  547. data/vendor/spinel/test/object_truthy.rb.expected +5 -0
  548. data/vendor/spinel/test/op_assign_user_operator.rb +36 -0
  549. data/vendor/spinel/test/open_class.rb +27 -0
  550. data/vendor/spinel/test/open_class.rb.expected +4 -0
  551. data/vendor/spinel/test/optional_string_param_method.rb +11 -0
  552. data/vendor/spinel/test/optional_string_param_method.rb.expected +3 -0
  553. data/vendor/spinel/test/param_inference_if_predicate.rb +90 -0
  554. data/vendor/spinel/test/param_inference_if_predicate.rb.expected +3 -0
  555. data/vendor/spinel/test/param_narrow_from_body_call.rb +34 -0
  556. data/vendor/spinel/test/param_narrow_from_body_call.rb.expected +2 -0
  557. data/vendor/spinel/test/param_widens_when_body_assigns_string.rb +21 -0
  558. data/vendor/spinel/test/param_widens_when_body_assigns_string.rb.expected +6 -0
  559. data/vendor/spinel/test/pattern.rb +41 -0
  560. data/vendor/spinel/test/pattern.rb.expected +9 -0
  561. data/vendor/spinel/test/poly.rb +24 -0
  562. data/vendor/spinel/test/poly.rb.expected +9 -0
  563. data/vendor/spinel/test/poly2.rb +34 -0
  564. data/vendor/spinel/test/poly2.rb.expected +9 -0
  565. data/vendor/spinel/test/poly_arith.rb +34 -0
  566. data/vendor/spinel/test/poly_arith.rb.expected +10 -0
  567. data/vendor/spinel/test/poly_array_literal_callnode_typed_elem.rb +37 -0
  568. data/vendor/spinel/test/poly_array_literal_callnode_typed_elem.rb.expected +9 -0
  569. data/vendor/spinel/test/poly_array_slot_literal.rb +41 -0
  570. data/vendor/spinel/test/poly_array_slot_sized_default.rb +33 -0
  571. data/vendor/spinel/test/poly_box_int_array.rb +13 -0
  572. data/vendor/spinel/test/poly_box_int_array.rb.expected +2 -0
  573. data/vendor/spinel/test/poly_dispatch_args_ret.rb +45 -0
  574. data/vendor/spinel/test/poly_dispatch_args_ret.rb.expected +4 -0
  575. data/vendor/spinel/test/poly_dispatch_arity_padding.rb +36 -0
  576. data/vendor/spinel/test/poly_dispatch_arity_truncate.rb +45 -0
  577. data/vendor/spinel/test/poly_dispatch_attr_reader.rb +44 -0
  578. data/vendor/spinel/test/poly_dispatch_attr_reader.rb.expected +4 -0
  579. data/vendor/spinel/test/poly_dispatch_builtin.rb +16 -0
  580. data/vendor/spinel/test/poly_dispatch_builtin.rb.expected +2 -0
  581. data/vendor/spinel/test/poly_dispatch_builtin_all.rb +34 -0
  582. data/vendor/spinel/test/poly_dispatch_builtin_all.rb.expected +8 -0
  583. data/vendor/spinel/test/poly_dispatch_ptr_array.rb +57 -0
  584. data/vendor/spinel/test/poly_dispatch_ptr_array.rb.expected +6 -0
  585. data/vendor/spinel/test/poly_equality_mixed_sites.rb +40 -0
  586. data/vendor/spinel/test/poly_equality_mixed_sites.rb.expected +10 -0
  587. data/vendor/spinel/test/poly_gc.rb +39 -0
  588. data/vendor/spinel/test/poly_gc.rb.expected +3 -0
  589. data/vendor/spinel/test/poly_hash_literal_from_ivar.rb +47 -0
  590. data/vendor/spinel/test/poly_hash_literal_from_ivar.rb.expected +5 -0
  591. data/vendor/spinel/test/poly_hash_with_range.rb +36 -0
  592. data/vendor/spinel/test/poly_hash_with_range.rb.expected +10 -0
  593. data/vendor/spinel/test/poly_hash_with_time.rb +32 -0
  594. data/vendor/spinel/test/poly_hash_with_time.rb.expected +8 -0
  595. data/vendor/spinel/test/poly_int_arith_auto_unify.rb +26 -0
  596. data/vendor/spinel/test/poly_int_arith_auto_unify.rb.expected +4 -0
  597. data/vendor/spinel/test/poly_int_bit_index.rb +50 -0
  598. data/vendor/spinel/test/poly_int_bit_index.rb.expected +14 -0
  599. data/vendor/spinel/test/poly_int_bitops_auto_unify.rb +20 -0
  600. data/vendor/spinel/test/poly_int_bitops_auto_unify.rb.expected +5 -0
  601. data/vendor/spinel/test/poly_is_a.rb +47 -0
  602. data/vendor/spinel/test/poly_is_a.rb.expected +10 -0
  603. data/vendor/spinel/test/poly_keyed_hash_method_dedup.rb +37 -0
  604. data/vendor/spinel/test/poly_keyed_hash_method_dedup.rb.expected +4 -0
  605. data/vendor/spinel/test/poly_keyed_hash_pipeline.rb +40 -0
  606. data/vendor/spinel/test/poly_keyed_hash_pipeline.rb.expected +2 -0
  607. data/vendor/spinel/test/poly_method_args.rb +23 -0
  608. data/vendor/spinel/test/poly_method_args.rb.expected +2 -0
  609. data/vendor/spinel/test/poly_method_mixed_return.rb +23 -0
  610. data/vendor/spinel/test/poly_method_mixed_return.rb.expected +2 -0
  611. data/vendor/spinel/test/poly_or_returns_value.rb +13 -0
  612. data/vendor/spinel/test/poly_or_returns_value.rb.expected +4 -0
  613. data/vendor/spinel/test/poly_recv_aref_box_arm.rb +41 -0
  614. data/vendor/spinel/test/poly_recv_aref_box_arm.rb.expected +4 -0
  615. data/vendor/spinel/test/poly_recv_aref_str_key.rb +42 -0
  616. data/vendor/spinel/test/poly_recv_aref_str_key.rb.expected +2 -0
  617. data/vendor/spinel/test/poly_recv_bracket_assign.rb +31 -0
  618. data/vendor/spinel/test/poly_recv_bracket_assign.rb.expected +1 -0
  619. data/vendor/spinel/test/poly_recv_each.rb +35 -0
  620. data/vendor/spinel/test/poly_recv_each.rb.expected +7 -0
  621. data/vendor/spinel/test/poly_return_value_class.rb +66 -0
  622. data/vendor/spinel/test/poly_return_value_class.rb.expected +7 -0
  623. data/vendor/spinel/test/poly_self_deref.rb +28 -0
  624. data/vendor/spinel/test/poly_self_deref.rb.expected +2 -0
  625. data/vendor/spinel/test/poly_shl_array_push_dispatch.rb +35 -0
  626. data/vendor/spinel/test/poly_shl_array_push_dispatch.rb.expected +5 -0
  627. data/vendor/spinel/test/poly_slice_assign.rb +26 -0
  628. data/vendor/spinel/test/poly_slice_assign.rb.expected +3 -0
  629. data/vendor/spinel/test/poly_str_append.rb +40 -0
  630. data/vendor/spinel/test/poly_str_append.rb.expected +2 -0
  631. data/vendor/spinel/test/poly_to_i_via_str_poly_hash.rb +19 -0
  632. data/vendor/spinel/test/poly_to_i_via_str_poly_hash.rb.expected +1 -0
  633. data/vendor/spinel/test/post_execution.rb +17 -0
  634. data/vendor/spinel/test/post_execution.rb.expected +4 -0
  635. data/vendor/spinel/test/pre_execution.rb +18 -0
  636. data/vendor/spinel/test/pre_execution.rb.expected +4 -0
  637. data/vendor/spinel/test/primitive_method_shadow.rb +48 -0
  638. data/vendor/spinel/test/primitive_method_shadow.rb.expected +4 -0
  639. data/vendor/spinel/test/primitive_method_shadow_int_recv.rb +47 -0
  640. data/vendor/spinel/test/primitive_method_shadow_int_recv.rb.expected +1 -0
  641. data/vendor/spinel/test/proc.rb +42 -0
  642. data/vendor/spinel/test/proc.rb.expected +8 -0
  643. data/vendor/spinel/test/proc_closure.rb +44 -0
  644. data/vendor/spinel/test/proc_closure.rb.expected +8 -0
  645. data/vendor/spinel/test/proc_hash_value.rb +27 -0
  646. data/vendor/spinel/test/proc_hash_value.rb.expected +1 -0
  647. data/vendor/spinel/test/ptr_array.rb +107 -0
  648. data/vendor/spinel/test/ptr_array.rb.expected +23 -0
  649. data/vendor/spinel/test/range.rb +130 -0
  650. data/vendor/spinel/test/range.rb.expected +61 -0
  651. data/vendor/spinel/test/redo.rb +263 -0
  652. data/vendor/spinel/test/redo.rb.expected +71 -0
  653. data/vendor/spinel/test/reduce_acc_shadow.rb +31 -0
  654. data/vendor/spinel/test/reduce_acc_shadow.rb.expected +5 -0
  655. data/vendor/spinel/test/regex.rb +152 -0
  656. data/vendor/spinel/test/regex.rb.expected +43 -0
  657. data/vendor/spinel/test/regexp.rb +34 -0
  658. data/vendor/spinel/test/regexp.rb.expected +12 -0
  659. data/vendor/spinel/test/reopen_class.rb +33 -0
  660. data/vendor/spinel/test/reopen_class.rb.expected +5 -0
  661. data/vendor/spinel/test/require/lib/greeter.rb +9 -0
  662. data/vendor/spinel/test/require/main.rb +5 -0
  663. data/vendor/spinel/test/require_dedup/lib/data.rb +2 -0
  664. data/vendor/spinel/test/require_dedup/lib/types.rb +1 -0
  665. data/vendor/spinel/test/require_dedup/main.rb +8 -0
  666. data/vendor/spinel/test/rescue.rb +48 -0
  667. data/vendor/spinel/test/rescue.rb.expected +7 -0
  668. data/vendor/spinel/test/rescue_modifier_assign.rb +24 -0
  669. data/vendor/spinel/test/rescue_modifier_assign.rb.expected +4 -0
  670. data/vendor/spinel/test/rightward_assign.rb +36 -0
  671. data/vendor/spinel/test/rightward_assign.rb.expected +6 -0
  672. data/vendor/spinel/test/runtime_widen_int_to_poly_array.rb +27 -0
  673. data/vendor/spinel/test/runtime_widen_int_to_poly_array.rb.expected +3 -0
  674. data/vendor/spinel/test/sample_user_method.rb +20 -0
  675. data/vendor/spinel/test/scan_ivars_inherited_slot.rb +32 -0
  676. data/vendor/spinel/test/scan_new_calls_class_scope.rb +35 -0
  677. data/vendor/spinel/test/scan_new_calls_class_scope.rb.expected +1 -0
  678. data/vendor/spinel/test/send.rb +15 -0
  679. data/vendor/spinel/test/send.rb.expected +2 -0
  680. data/vendor/spinel/test/shareable_constant.rb +10 -0
  681. data/vendor/spinel/test/shareable_constant.rb.expected +2 -0
  682. data/vendor/spinel/test/sized_poly_array_nil_n.rb +37 -0
  683. data/vendor/spinel/test/sized_poly_array_nil_n.rb.expected +3 -0
  684. data/vendor/spinel/test/source_file.rb +37 -0
  685. data/vendor/spinel/test/source_file.rb.expected +8 -0
  686. data/vendor/spinel/test/splat_call.rb +72 -0
  687. data/vendor/spinel/test/splat_call.rb.expected +35 -0
  688. data/vendor/spinel/test/splat_destructure.rb +56 -0
  689. data/vendor/spinel/test/splat_destructure.rb.expected +36 -0
  690. data/vendor/spinel/test/splat_destructure_poly.rb +26 -0
  691. data/vendor/spinel/test/splat_destructure_poly.rb.expected +8 -0
  692. data/vendor/spinel/test/stdlib.rb +28 -0
  693. data/vendor/spinel/test/stdlib.rb.expected +5 -0
  694. data/vendor/spinel/test/stringio.rb +84 -0
  695. data/vendor/spinel/test/stringio.rb.expected +27 -0
  696. data/vendor/spinel/test/strip_nullable_int_cast.rb +24 -0
  697. data/vendor/spinel/test/strip_nullable_int_cast.rb.expected +1 -0
  698. data/vendor/spinel/test/struct.rb +25 -0
  699. data/vendor/spinel/test/struct.rb.expected +8 -0
  700. data/vendor/spinel/test/struct_inherit.rb +28 -0
  701. data/vendor/spinel/test/struct_inherit.rb.expected +7 -0
  702. data/vendor/spinel/test/struct_kw.rb +16 -0
  703. data/vendor/spinel/test/struct_kw.rb.expected +5 -0
  704. data/vendor/spinel/test/subclass_inherits_module_parent.rb +40 -0
  705. data/vendor/spinel/test/subclass_inherits_module_parent.rb.expected +3 -0
  706. data/vendor/spinel/test/super_arg_cross_class_cast.rb +39 -0
  707. data/vendor/spinel/test/super_arg_cross_class_cast.rb.expected +2 -0
  708. data/vendor/spinel/test/super_forwarding.rb +25 -0
  709. data/vendor/spinel/test/super_forwarding.rb.expected +3 -0
  710. data/vendor/spinel/test/sym_case.rb +15 -0
  711. data/vendor/spinel/test/sym_case.rb.expected +4 -0
  712. data/vendor/spinel/test/sym_poly_hash_merge.rb +47 -0
  713. data/vendor/spinel/test/sym_poly_hash_merge.rb.expected +11 -0
  714. data/vendor/spinel/test/symbol_ivar_reassign.rb +25 -0
  715. data/vendor/spinel/test/symbol_ivar_reassign.rb.expected +2 -0
  716. data/vendor/spinel/test/three_level_array_outer_index.rb +87 -0
  717. data/vendor/spinel/test/three_level_array_outer_index.rb.expected +17 -0
  718. data/vendor/spinel/test/toplevel_ivar_array.rb +19 -0
  719. data/vendor/spinel/test/toplevel_ivar_array.rb.expected +4 -0
  720. data/vendor/spinel/test/truncate_module_method.rb +46 -0
  721. data/vendor/spinel/test/truncate_module_method.rb.expected +6 -0
  722. data/vendor/spinel/test/unbox_poly_index_in_dispatch.rb +20 -0
  723. data/vendor/spinel/test/unbox_poly_index_in_dispatch.rb.expected +1 -0
  724. data/vendor/spinel/test/undef.rb +33 -0
  725. data/vendor/spinel/test/undef.rb.expected +2 -0
  726. data/vendor/spinel/test/user_method_named_like_mutator.rb +30 -0
  727. data/vendor/spinel/test/user_method_named_like_mutator.rb.expected +2 -0
  728. data/vendor/spinel/test/value_type_ctor_gc_save.rb +46 -0
  729. data/vendor/spinel/test/value_type_ctor_gc_save.rb.expected +3 -0
  730. data/vendor/spinel/test/widen_int_obj_to_poly.rb +29 -0
  731. data/vendor/spinel/test/yield.rb +67 -0
  732. data/vendor/spinel/test/yield.rb.expected +5 -0
  733. data/vendor/spinel/test/yield_method_call_in_method_body.rb +58 -0
  734. data/vendor/spinel/test/yield_method_call_in_method_body.rb.expected +4 -0
  735. metadata +778 -0
@@ -0,0 +1,1586 @@
1
+ /*
2
+ * spinel_parse.c - Prism AST Serializer (C version)
3
+ *
4
+ * Equivalent to spinel_parse.rb but links with libprism directly.
5
+ * Parses Ruby source and outputs line-based text AST for spinel_codegen.
6
+ *
7
+ * Build: cc -O2 -I$(PRISM)/include spinel_parse.c -L$(PRISM)/build -lprism -o spinel_parse
8
+ *
9
+ * Output format:
10
+ * ROOT <id>
11
+ * N <id> <type> - node declaration
12
+ * S <id> <field> <escaped> - string field
13
+ * I <id> <field> <integer> - integer field
14
+ * F <id> <field> <float> - float field
15
+ * R <id> <field> <ref_id> - reference (-1 for nil)
16
+ * A <id> <field> <ids> - array of references
17
+ */
18
+
19
+ #include <stdio.h>
20
+ #include <stdlib.h>
21
+ #include <string.h>
22
+ #include <stdarg.h>
23
+ #include <prism.h>
24
+
25
+ /* ---- Output buffer ---- */
26
+ static char **lines;
27
+ static int line_count;
28
+ static int line_cap;
29
+ static int node_counter;
30
+
31
+ static void out_add(const char *fmt, ...) {
32
+ va_list ap;
33
+ va_start(ap, fmt);
34
+ char buf[4096];
35
+ vsnprintf(buf, sizeof(buf), fmt, ap);
36
+ va_end(ap);
37
+ if (line_count >= line_cap) {
38
+ line_cap = line_cap * 2 + 256;
39
+ lines = realloc(lines, sizeof(char *) * line_cap);
40
+ }
41
+ lines[line_count++] = strdup(buf);
42
+ }
43
+
44
+ /* ---- Name from constant pool ---- */
45
+ static const pm_parser_t *g_parser;
46
+ static const char *g_source_file = "";
47
+ static char *g_source_file_escaped = NULL; /* escape_str(g_source_file), set once at init */
48
+
49
+ static char *cstr(pm_constant_id_t id) {
50
+ if (id == 0) return strdup("");
51
+ pm_constant_t *c = &g_parser->constant_pool.constants[id - 1];
52
+ char *buf = malloc(c->length + 1);
53
+ memcpy(buf, c->start, c->length);
54
+ buf[c->length] = '\0';
55
+ return buf;
56
+ }
57
+
58
+ /* ---- String escaping ---- */
59
+ static char *escape_str(const uint8_t *src, size_t len) {
60
+ /* Worst case: every char becomes %XX = 3x */
61
+ char *out = malloc(len * 3 + 1);
62
+ size_t j = 0;
63
+ for (size_t i = 0; i < len; i++) {
64
+ uint8_t c = src[i];
65
+ if (c == '%') { out[j++]='%'; out[j++]='2'; out[j++]='5'; }
66
+ else if (c == '\n') { out[j++]='%'; out[j++]='0'; out[j++]='A'; }
67
+ else if (c == '\r') { out[j++]='%'; out[j++]='0'; out[j++]='D'; }
68
+ else if (c == '\t') { out[j++]='%'; out[j++]='0'; out[j++]='9'; }
69
+ else if (c == ' ') { out[j++]='%'; out[j++]='2'; out[j++]='0'; }
70
+ else out[j++] = c;
71
+ }
72
+ out[j] = '\0';
73
+ return out;
74
+ }
75
+
76
+ static char *escape_pm_string(const pm_string_t *s) {
77
+ return escape_str(pm_string_source(s), pm_string_length(s));
78
+ }
79
+
80
+ /* Convert "PM_FOO_BAR_NODE" -> "FooBarNode" into `out`, truncated to
81
+ out_size-1 chars + NUL. Prism's node-type strings are pure ASCII
82
+ upper + underscore so we add 32 to lowercase non-leading letters. */
83
+ static size_t prism_kind_to_pascal(const char *raw, char *out, size_t out_size) {
84
+ if (out_size == 0) return 0;
85
+ if (strncmp(raw, "PM_", 3) == 0) raw += 3;
86
+ size_t j = 0;
87
+ int upper = 1;
88
+ for (; *raw && j < out_size - 1; raw++) {
89
+ if (*raw == '_') { upper = 1; continue; }
90
+ out[j++] = upper ? *raw : (char)(*raw + 32);
91
+ upper = 0;
92
+ }
93
+ out[j] = '\0';
94
+ return j;
95
+ }
96
+
97
+ /* ---- Forward ---- */
98
+ static int flatten(pm_node_t *node);
99
+
100
+ /* ---- Emit helpers ---- */
101
+ static void emit_str(int id, const char *field, const char *val) {
102
+ out_add("S %d %s %s", id, field, val);
103
+ }
104
+
105
+ static void emit_int(int id, const char *field, long long val) {
106
+ out_add("I %d %s %lld", id, field, val);
107
+ }
108
+
109
+ static void emit_float(int id, const char *field, double val) {
110
+ char buf[64];
111
+ snprintf(buf, sizeof(buf), "%.17g", val);
112
+ /* Ensure there's a decimal point (Ruby outputs 0.0, not 0) */
113
+ if (!strchr(buf, '.') && !strchr(buf, 'e') && !strchr(buf, 'E'))
114
+ strcat(buf, ".0");
115
+ out_add("F %d %s %s", id, field, buf);
116
+ }
117
+
118
+ static void emit_ref(int id, const char *field, pm_node_t *child) {
119
+ int cid = child ? flatten(child) : -1;
120
+ out_add("R %d %s %d", id, field, cid);
121
+ }
122
+
123
+ static void emit_node_array(int id, const char *field, pm_node_list_t *list) {
124
+ if (!list || list->size == 0) {
125
+ out_add("A %d %s ", id, field);
126
+ return;
127
+ }
128
+ int *ids = malloc(sizeof(int) * list->size);
129
+ for (size_t i = 0; i < list->size; i++)
130
+ ids[i] = flatten(list->nodes[i]);
131
+ /* Build comma-separated string */
132
+ char buf[65536];
133
+ int pos = 0;
134
+ for (size_t i = 0; i < list->size; i++) {
135
+ if (i > 0) buf[pos++] = ',';
136
+ pos += snprintf(buf + pos, sizeof(buf) - pos, "%d", ids[i]);
137
+ }
138
+ buf[pos] = '\0';
139
+ out_add("A %d %s %s", id, field, buf);
140
+ free(ids);
141
+ }
142
+
143
+ /* ---- Integer value extraction ---- */
144
+ static long long pm_int_value(pm_integer_t *integer) {
145
+ long long val = 0;
146
+ if (integer->length == 0) {
147
+ val = (long long)integer->value;
148
+ } else {
149
+ /* Large integer - approximate with first word */
150
+ val = (long long)integer->value;
151
+ /* TODO: proper bignum support */
152
+ }
153
+ if (integer->negative) val = -val;
154
+ return val;
155
+ }
156
+
157
+ /* ---- Main flattening ---- */
158
+ static int flatten(pm_node_t *node) {
159
+ if (!node) return -1;
160
+
161
+ int id = node_counter++;
162
+ pm_node_type_t t = PM_NODE_TYPE(node);
163
+
164
+ #define N(type_name) out_add("N %d " type_name, id)
165
+ #define S(field, val) do { char *_e = (val); emit_str(id, field, _e); free(_e); } while(0)
166
+ #define I(field, val) emit_int(id, field, val)
167
+ #define F(field, val) emit_float(id, field, val)
168
+ #define R(field, child) emit_ref(id, field, (pm_node_t *)(child))
169
+ #define A(field, list) emit_node_array(id, field, list)
170
+ #define NAME(field, cid) do { char *_n = cstr(cid); char *_e = escape_str((const uint8_t *)_n, strlen(_n)); emit_str(id, field, _e); free(_e); free(_n); } while(0)
171
+
172
+ switch (t) {
173
+ case PM_PROGRAM_NODE: {
174
+ pm_program_node_t *n = (pm_program_node_t *)node;
175
+ N("ProgramNode");
176
+ R("statements", n->statements);
177
+ break;
178
+ }
179
+ case PM_STATEMENTS_NODE: {
180
+ pm_statements_node_t *n = (pm_statements_node_t *)node;
181
+ N("StatementsNode");
182
+ A("body", &n->body);
183
+ break;
184
+ }
185
+ case PM_CLASS_NODE: {
186
+ pm_class_node_t *n = (pm_class_node_t *)node;
187
+ N("ClassNode");
188
+ R("constant_path", n->constant_path);
189
+ R("superclass", n->superclass);
190
+ R("body", n->body);
191
+ break;
192
+ }
193
+ case PM_MODULE_NODE: {
194
+ pm_module_node_t *n = (pm_module_node_t *)node;
195
+ N("ModuleNode");
196
+ R("constant_path", n->constant_path);
197
+ R("body", n->body);
198
+ break;
199
+ }
200
+ case PM_SINGLETON_CLASS_NODE: {
201
+ /* `class << self; ...; end` — the singleton class block. We
202
+ only support `expression == SelfNode` today (i.e. the
203
+ enclosing class/module's singleton). The body is flattened
204
+ up one level so codegen sees `attr_accessor :x` / `def foo`
205
+ inside the parent ClassNode/ModuleNode body, and the
206
+ SingletonClassNode marker survives so dispatch can route
207
+ methods/accessors to the class-method path. */
208
+ pm_singleton_class_node_t *n = (pm_singleton_class_node_t *)node;
209
+ N("SingletonClassNode");
210
+ R("expression", n->expression);
211
+ R("body", n->body);
212
+ break;
213
+ }
214
+ case PM_DEF_NODE: {
215
+ pm_def_node_t *n = (pm_def_node_t *)node;
216
+ N("DefNode");
217
+ NAME("name", n->name);
218
+ R("parameters", n->parameters);
219
+ R("body", n->body);
220
+ R("receiver", n->receiver);
221
+ break;
222
+ }
223
+ case PM_CALL_NODE: {
224
+ pm_call_node_t *n = (pm_call_node_t *)node;
225
+ N("CallNode");
226
+ NAME("name", n->name);
227
+ R("receiver", n->receiver);
228
+ R("arguments", n->arguments);
229
+ R("block", n->block);
230
+ if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
231
+ S("call_operator", escape_str((const uint8_t *)"&.", 2));
232
+ }
233
+ break;
234
+ }
235
+ case PM_CONSTANT_WRITE_NODE: {
236
+ pm_constant_write_node_t *n = (pm_constant_write_node_t *)node;
237
+ N("ConstantWriteNode");
238
+ NAME("name", n->name);
239
+ R("value", n->value);
240
+ break;
241
+ }
242
+ case PM_CONSTANT_PATH_WRITE_NODE: {
243
+ pm_constant_path_write_node_t *n = (pm_constant_path_write_node_t *)node;
244
+ N("ConstantPathWriteNode");
245
+ R("value", n->value);
246
+ R("target", n->target);
247
+ break;
248
+ }
249
+ case PM_CONSTANT_READ_NODE: {
250
+ pm_constant_read_node_t *n = (pm_constant_read_node_t *)node;
251
+ N("ConstantReadNode");
252
+ NAME("name", n->name);
253
+ break;
254
+ }
255
+ case PM_CONSTANT_PATH_NODE: {
256
+ pm_constant_path_node_t *n = (pm_constant_path_node_t *)node;
257
+ N("ConstantPathNode");
258
+ R("parent", n->parent);
259
+ NAME("name", n->name);
260
+ break;
261
+ }
262
+ case PM_LOCAL_VARIABLE_WRITE_NODE: {
263
+ pm_local_variable_write_node_t *n = (pm_local_variable_write_node_t *)node;
264
+ N("LocalVariableWriteNode");
265
+ NAME("name", n->name);
266
+ R("value", n->value);
267
+ break;
268
+ }
269
+ case PM_LOCAL_VARIABLE_READ_NODE: {
270
+ pm_local_variable_read_node_t *n = (pm_local_variable_read_node_t *)node;
271
+ N("LocalVariableReadNode");
272
+ NAME("name", n->name);
273
+ break;
274
+ }
275
+ case PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: {
276
+ pm_local_variable_operator_write_node_t *n = (pm_local_variable_operator_write_node_t *)node;
277
+ N("LocalVariableOperatorWriteNode");
278
+ NAME("name", n->name);
279
+ NAME("binary_operator", n->binary_operator);
280
+ R("value", n->value);
281
+ break;
282
+ }
283
+ case PM_LOCAL_VARIABLE_OR_WRITE_NODE: {
284
+ pm_local_variable_or_write_node_t *n = (pm_local_variable_or_write_node_t *)node;
285
+ N("LocalVariableOrWriteNode");
286
+ NAME("name", n->name);
287
+ R("value", n->value);
288
+ break;
289
+ }
290
+ case PM_LOCAL_VARIABLE_AND_WRITE_NODE: {
291
+ pm_local_variable_and_write_node_t *n = (pm_local_variable_and_write_node_t *)node;
292
+ N("LocalVariableAndWriteNode");
293
+ NAME("name", n->name);
294
+ R("value", n->value);
295
+ break;
296
+ }
297
+ case PM_LOCAL_VARIABLE_TARGET_NODE: {
298
+ pm_local_variable_target_node_t *n = (pm_local_variable_target_node_t *)node;
299
+ N("LocalVariableTargetNode");
300
+ NAME("name", n->name);
301
+ break;
302
+ }
303
+ case PM_INSTANCE_VARIABLE_WRITE_NODE: {
304
+ pm_instance_variable_write_node_t *n = (pm_instance_variable_write_node_t *)node;
305
+ N("InstanceVariableWriteNode");
306
+ NAME("name", n->name);
307
+ R("value", n->value);
308
+ break;
309
+ }
310
+ case PM_INSTANCE_VARIABLE_READ_NODE: {
311
+ pm_instance_variable_read_node_t *n = (pm_instance_variable_read_node_t *)node;
312
+ N("InstanceVariableReadNode");
313
+ NAME("name", n->name);
314
+ break;
315
+ }
316
+ case PM_INSTANCE_VARIABLE_TARGET_NODE: {
317
+ pm_instance_variable_target_node_t *n = (pm_instance_variable_target_node_t *)node;
318
+ N("InstanceVariableTargetNode");
319
+ NAME("name", n->name);
320
+ break;
321
+ }
322
+ case PM_CALL_TARGET_NODE: {
323
+ pm_call_target_node_t *n = (pm_call_target_node_t *)node;
324
+ N("CallTargetNode");
325
+ NAME("name", n->name);
326
+ R("receiver", n->receiver);
327
+ break;
328
+ }
329
+ case PM_CONSTANT_TARGET_NODE: {
330
+ pm_constant_target_node_t *n = (pm_constant_target_node_t *)node;
331
+ N("ConstantTargetNode");
332
+ NAME("name", n->name);
333
+ break;
334
+ }
335
+ case PM_INSTANCE_VARIABLE_AND_WRITE_NODE: {
336
+ pm_instance_variable_and_write_node_t *n = (pm_instance_variable_and_write_node_t *)node;
337
+ N("InstanceVariableAndWriteNode");
338
+ NAME("name", n->name);
339
+ R("value", n->value);
340
+ break;
341
+ }
342
+ case PM_INSTANCE_VARIABLE_OR_WRITE_NODE: {
343
+ pm_instance_variable_or_write_node_t *n = (pm_instance_variable_or_write_node_t *)node;
344
+ N("InstanceVariableOrWriteNode");
345
+ NAME("name", n->name);
346
+ R("value", n->value);
347
+ break;
348
+ }
349
+ case PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: {
350
+ pm_instance_variable_operator_write_node_t *n = (pm_instance_variable_operator_write_node_t *)node;
351
+ N("InstanceVariableOperatorWriteNode");
352
+ NAME("name", n->name);
353
+ NAME("binary_operator", n->binary_operator);
354
+ R("value", n->value);
355
+ break;
356
+ }
357
+ case PM_CLASS_VARIABLE_WRITE_NODE: {
358
+ pm_class_variable_write_node_t *n = (pm_class_variable_write_node_t *)node;
359
+ N("ClassVariableWriteNode");
360
+ NAME("name", n->name);
361
+ R("value", n->value);
362
+ break;
363
+ }
364
+ case PM_CLASS_VARIABLE_READ_NODE: {
365
+ pm_class_variable_read_node_t *n = (pm_class_variable_read_node_t *)node;
366
+ N("ClassVariableReadNode");
367
+ NAME("name", n->name);
368
+ break;
369
+ }
370
+ case PM_INDEX_OPERATOR_WRITE_NODE: {
371
+ pm_index_operator_write_node_t *n = (pm_index_operator_write_node_t *)node;
372
+ N("IndexOperatorWriteNode");
373
+ NAME("binary_operator", n->binary_operator);
374
+ R("receiver", n->receiver);
375
+ R("arguments", n->arguments);
376
+ R("value", n->value);
377
+ break;
378
+ }
379
+ case PM_INDEX_AND_WRITE_NODE: {
380
+ pm_index_and_write_node_t *n = (pm_index_and_write_node_t *)node;
381
+ N("IndexAndWriteNode");
382
+ R("receiver", n->receiver);
383
+ R("arguments", n->arguments);
384
+ R("value", n->value);
385
+ break;
386
+ }
387
+ case PM_INDEX_OR_WRITE_NODE: {
388
+ pm_index_or_write_node_t *n = (pm_index_or_write_node_t *)node;
389
+ N("IndexOrWriteNode");
390
+ R("receiver", n->receiver);
391
+ R("arguments", n->arguments);
392
+ R("value", n->value);
393
+ break;
394
+ }
395
+ case PM_INDEX_TARGET_NODE: {
396
+ pm_index_target_node_t *n = (pm_index_target_node_t *)node;
397
+ N("IndexTargetNode");
398
+ R("receiver", n->receiver);
399
+ R("arguments", n->arguments);
400
+ break;
401
+ }
402
+ case PM_CALL_OPERATOR_WRITE_NODE: {
403
+ pm_call_operator_write_node_t *n = (pm_call_operator_write_node_t *)node;
404
+ N("CallOperatorWriteNode");
405
+ R("receiver", n->receiver);
406
+ NAME("name", n->read_name);
407
+ NAME("binary_operator", n->binary_operator);
408
+ R("value", n->value);
409
+ if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
410
+ S("call_operator", escape_str((const uint8_t *)"&.", 2));
411
+ }
412
+ break;
413
+ }
414
+ case PM_CALL_AND_WRITE_NODE: {
415
+ pm_call_and_write_node_t *n = (pm_call_and_write_node_t *)node;
416
+ N("CallAndWriteNode");
417
+ R("receiver", n->receiver);
418
+ NAME("name", n->read_name);
419
+ R("value", n->value);
420
+ if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
421
+ S("call_operator", escape_str((const uint8_t *)"&.", 2));
422
+ }
423
+ break;
424
+ }
425
+ case PM_CALL_OR_WRITE_NODE: {
426
+ pm_call_or_write_node_t *n = (pm_call_or_write_node_t *)node;
427
+ N("CallOrWriteNode");
428
+ R("receiver", n->receiver);
429
+ NAME("name", n->read_name);
430
+ R("value", n->value);
431
+ if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
432
+ S("call_operator", escape_str((const uint8_t *)"&.", 2));
433
+ }
434
+ break;
435
+ }
436
+ case PM_GLOBAL_VARIABLE_WRITE_NODE: {
437
+ pm_global_variable_write_node_t *n = (pm_global_variable_write_node_t *)node;
438
+ N("GlobalVariableWriteNode");
439
+ NAME("name", n->name);
440
+ R("value", n->value);
441
+ break;
442
+ }
443
+ case PM_GLOBAL_VARIABLE_READ_NODE: {
444
+ pm_global_variable_read_node_t *n = (pm_global_variable_read_node_t *)node;
445
+ N("GlobalVariableReadNode");
446
+ NAME("name", n->name);
447
+ break;
448
+ }
449
+ case PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: {
450
+ pm_global_variable_operator_write_node_t *n = (pm_global_variable_operator_write_node_t *)node;
451
+ N("GlobalVariableOperatorWriteNode");
452
+ NAME("name", n->name);
453
+ NAME("binary_operator", n->binary_operator);
454
+ R("value", n->value);
455
+ break;
456
+ }
457
+ case PM_GLOBAL_VARIABLE_OR_WRITE_NODE: {
458
+ pm_global_variable_or_write_node_t *n = (pm_global_variable_or_write_node_t *)node;
459
+ N("GlobalVariableOrWriteNode");
460
+ NAME("name", n->name);
461
+ R("value", n->value);
462
+ break;
463
+ }
464
+ case PM_GLOBAL_VARIABLE_AND_WRITE_NODE: {
465
+ pm_global_variable_and_write_node_t *n = (pm_global_variable_and_write_node_t *)node;
466
+ N("GlobalVariableAndWriteNode");
467
+ NAME("name", n->name);
468
+ R("value", n->value);
469
+ break;
470
+ }
471
+ case PM_GLOBAL_VARIABLE_TARGET_NODE: {
472
+ pm_global_variable_target_node_t *n = (pm_global_variable_target_node_t *)node;
473
+ N("GlobalVariableTargetNode");
474
+ NAME("name", n->name);
475
+ break;
476
+ }
477
+ case PM_NO_KEYWORDS_PARAMETER_NODE: {
478
+ /* `def f(**nil)` -- explicit kwarg rejection. Spinel's keyword-arg
479
+ handling is already conservative (only known keys accepted),
480
+ so the explicit "no keywords" marker is effectively a no-op
481
+ at the codegen level. We emit the node so a ParametersNode
482
+ carrying it doesn't leave a NULL keyword slot, but the
483
+ compile-time effect is nothing. */
484
+ N("NoKeywordsParameterNode");
485
+ break;
486
+ }
487
+ case PM_INTEGER_NODE: {
488
+ pm_integer_node_t *n = (pm_integer_node_t *)node;
489
+ N("IntegerNode");
490
+ I("value", pm_int_value(&n->value));
491
+ break;
492
+ }
493
+ case PM_FLOAT_NODE: {
494
+ pm_float_node_t *n = (pm_float_node_t *)node;
495
+ N("FloatNode");
496
+ F("value", n->value);
497
+ break;
498
+ }
499
+ case PM_STRING_NODE: {
500
+ pm_string_node_t *n = (pm_string_node_t *)node;
501
+ N("StringNode");
502
+ S("content", escape_pm_string(&n->unescaped));
503
+ break;
504
+ }
505
+ case PM_INTERPOLATED_STRING_NODE: {
506
+ pm_interpolated_string_node_t *n = (pm_interpolated_string_node_t *)node;
507
+ N("InterpolatedStringNode");
508
+ A("parts", &n->parts);
509
+ break;
510
+ }
511
+ case PM_EMBEDDED_STATEMENTS_NODE: {
512
+ pm_embedded_statements_node_t *n = (pm_embedded_statements_node_t *)node;
513
+ N("EmbeddedStatementsNode");
514
+ R("statements", n->statements);
515
+ break;
516
+ }
517
+ case PM_SYMBOL_NODE: {
518
+ pm_symbol_node_t *n = (pm_symbol_node_t *)node;
519
+ N("SymbolNode");
520
+ S("value", escape_pm_string(&n->unescaped));
521
+ break;
522
+ }
523
+ case PM_TRUE_NODE:
524
+ N("TrueNode");
525
+ break;
526
+ case PM_FALSE_NODE:
527
+ N("FalseNode");
528
+ break;
529
+ case PM_NIL_NODE:
530
+ N("NilNode");
531
+ break;
532
+ case PM_SELF_NODE:
533
+ N("SelfNode");
534
+ break;
535
+ case PM_ARRAY_NODE: {
536
+ pm_array_node_t *n = (pm_array_node_t *)node;
537
+ N("ArrayNode");
538
+ A("elements", &n->elements);
539
+ break;
540
+ }
541
+ case PM_HASH_NODE: {
542
+ pm_hash_node_t *n = (pm_hash_node_t *)node;
543
+ N("HashNode");
544
+ A("elements", &n->elements);
545
+ break;
546
+ }
547
+ case PM_ASSOC_NODE: {
548
+ pm_assoc_node_t *n = (pm_assoc_node_t *)node;
549
+ N("AssocNode");
550
+ R("key", n->key);
551
+ /* Hash shorthand `{ x: }` lowers to an AssocNode whose value is a
552
+ PM_IMPLICIT_NODE. The top-level PM_IMPLICIT_NODE case below
553
+ handles the unwrap by recursing into n->value at the same id
554
+ slot, so the codegen never sees the implicit wrapper here. */
555
+ R("value", n->value);
556
+ break;
557
+ }
558
+ case PM_KEYWORD_HASH_NODE: {
559
+ pm_keyword_hash_node_t *n = (pm_keyword_hash_node_t *)node;
560
+ N("KeywordHashNode");
561
+ A("elements", &n->elements);
562
+ break;
563
+ }
564
+ case PM_RANGE_NODE: {
565
+ pm_range_node_t *n = (pm_range_node_t *)node;
566
+ N("RangeNode");
567
+ R("left", n->left);
568
+ R("right", n->right);
569
+ /* PM_RANGE_FLAGS_EXCLUDE_END = 4. Codegen reads bit 2 to decide
570
+ whether `..` (inclusive) or `...` (exclusive). */
571
+ I("flags", n->base.flags);
572
+ break;
573
+ }
574
+ case PM_IF_NODE: {
575
+ pm_if_node_t *n = (pm_if_node_t *)node;
576
+ N("IfNode");
577
+ R("predicate", n->predicate);
578
+ R("statements", n->statements);
579
+ R("subsequent", n->subsequent);
580
+ break;
581
+ }
582
+ case PM_ELSE_NODE: {
583
+ pm_else_node_t *n = (pm_else_node_t *)node;
584
+ N("ElseNode");
585
+ R("statements", n->statements);
586
+ break;
587
+ }
588
+ case PM_UNLESS_NODE: {
589
+ pm_unless_node_t *n = (pm_unless_node_t *)node;
590
+ N("UnlessNode");
591
+ R("predicate", n->predicate);
592
+ R("statements", n->statements);
593
+ R("else_clause", n->else_clause);
594
+ break;
595
+ }
596
+ case PM_WHILE_NODE: {
597
+ pm_while_node_t *n = (pm_while_node_t *)node;
598
+ N("WhileNode");
599
+ R("predicate", n->predicate);
600
+ R("statements", n->statements);
601
+ /* PM_LOOP_FLAGS_BEGIN_MODIFIER = 4 (bit 2): begin..end while form,
602
+ which is a post-test loop (body runs at least once). The codegen
603
+ reads bit 2 to decide between `while (cond) {}` and `do {} while (cond);`. */
604
+ I("flags", n->base.flags);
605
+ break;
606
+ }
607
+ case PM_UNTIL_NODE: {
608
+ pm_until_node_t *n = (pm_until_node_t *)node;
609
+ N("UntilNode");
610
+ R("predicate", n->predicate);
611
+ R("statements", n->statements);
612
+ I("flags", n->base.flags);
613
+ break;
614
+ }
615
+ case PM_FOR_NODE: {
616
+ pm_for_node_t *n = (pm_for_node_t *)node;
617
+ N("ForNode");
618
+ R("index", n->index);
619
+ R("collection", n->collection);
620
+ R("statements", n->statements);
621
+ break;
622
+ }
623
+ case PM_CASE_NODE: {
624
+ pm_case_node_t *n = (pm_case_node_t *)node;
625
+ N("CaseNode");
626
+ R("predicate", n->predicate);
627
+ A("conditions", &n->conditions);
628
+ R("else_clause", n->else_clause);
629
+ break;
630
+ }
631
+ case PM_CASE_MATCH_NODE: {
632
+ pm_case_match_node_t *n = (pm_case_match_node_t *)node;
633
+ N("CaseMatchNode");
634
+ R("predicate", n->predicate);
635
+ A("conditions", &n->conditions);
636
+ R("else_clause", n->else_clause);
637
+ break;
638
+ }
639
+ case PM_WHEN_NODE: {
640
+ pm_when_node_t *n = (pm_when_node_t *)node;
641
+ N("WhenNode");
642
+ A("conditions", &n->conditions);
643
+ R("statements", n->statements);
644
+ break;
645
+ }
646
+ case PM_IN_NODE: {
647
+ pm_in_node_t *n = (pm_in_node_t *)node;
648
+ N("InNode");
649
+ R("pattern", n->pattern);
650
+ R("statements", n->statements);
651
+ break;
652
+ }
653
+ case PM_BEGIN_NODE: {
654
+ pm_begin_node_t *n = (pm_begin_node_t *)node;
655
+ N("BeginNode");
656
+ R("statements", n->statements);
657
+ R("rescue_clause", n->rescue_clause);
658
+ R("ensure_clause", n->ensure_clause);
659
+ R("else_clause", n->else_clause);
660
+ break;
661
+ }
662
+ case PM_ENSURE_NODE: {
663
+ pm_ensure_node_t *n = (pm_ensure_node_t *)node;
664
+ N("EnsureNode");
665
+ R("statements", n->statements);
666
+ break;
667
+ }
668
+ case PM_RESCUE_NODE: {
669
+ pm_rescue_node_t *n = (pm_rescue_node_t *)node;
670
+ N("RescueNode");
671
+ A("exceptions", &n->exceptions);
672
+ R("reference", n->reference);
673
+ R("statements", n->statements);
674
+ R("subsequent", n->subsequent);
675
+ break;
676
+ }
677
+ case PM_RESCUE_MODIFIER_NODE: {
678
+ pm_rescue_modifier_node_t *n = (pm_rescue_modifier_node_t *)node;
679
+ N("RescueModifierNode");
680
+ R("expression", n->expression);
681
+ R("rescue_expression", n->rescue_expression);
682
+ break;
683
+ }
684
+ case PM_RETURN_NODE: {
685
+ pm_return_node_t *n = (pm_return_node_t *)node;
686
+ N("ReturnNode");
687
+ R("arguments", n->arguments);
688
+ break;
689
+ }
690
+ case PM_BREAK_NODE:
691
+ N("BreakNode");
692
+ break;
693
+ case PM_NEXT_NODE:
694
+ N("NextNode");
695
+ break;
696
+ case PM_RETRY_NODE:
697
+ N("RetryNode");
698
+ break;
699
+ case PM_YIELD_NODE: {
700
+ pm_yield_node_t *n = (pm_yield_node_t *)node;
701
+ N("YieldNode");
702
+ R("arguments", n->arguments);
703
+ break;
704
+ }
705
+ case PM_BLOCK_NODE: {
706
+ pm_block_node_t *n = (pm_block_node_t *)node;
707
+ N("BlockNode");
708
+ /* Serialize block parameters */
709
+ if (n->parameters) {
710
+ if (PM_NODE_TYPE(n->parameters) == PM_BLOCK_PARAMETERS_NODE) {
711
+ pm_block_parameters_node_t *bp = (pm_block_parameters_node_t *)n->parameters;
712
+ int bpid = node_counter++;
713
+ out_add("N %d BlockParametersNode", bpid);
714
+ if (bp->parameters) {
715
+ emit_ref(bpid, "parameters", (pm_node_t *)bp->parameters);
716
+ }
717
+ out_add("R %d %s %d", id, "parameters", bpid);
718
+ } else if (PM_NODE_TYPE(n->parameters) == PM_NUMBERED_PARAMETERS_NODE) {
719
+ pm_numbered_parameters_node_t *np = (pm_numbered_parameters_node_t *)n->parameters;
720
+ int npid = node_counter++;
721
+ out_add("N %d NumberedParametersNode", npid);
722
+ emit_int(npid, "maximum", np->maximum);
723
+ out_add("R %d %s %d", id, "parameters", npid);
724
+ } else {
725
+ R("parameters", n->parameters);
726
+ }
727
+ }
728
+ R("body", n->body);
729
+ break;
730
+ }
731
+ case PM_PARAMETERS_NODE: {
732
+ pm_parameters_node_t *n = (pm_parameters_node_t *)node;
733
+ N("ParametersNode");
734
+ A("requireds", &n->requireds);
735
+ A("optionals", &n->optionals);
736
+ A("keywords", &n->keywords);
737
+ if (n->rest) R("rest", n->rest);
738
+ if (n->block) R("block", n->block);
739
+ A("posts", &n->posts);
740
+ /* Surface keyword_rest so the new PM_NO_KEYWORDS_PARAMETER_NODE
741
+ case below is reachable. Existing collect_params_str walker
742
+ only acts on KeywordRestParameterNode (`**kw`), so the
743
+ NoKeywordsParameter (`**nil`) marker passes through as a
744
+ no-op which matches its compile-time semantics. */
745
+ if (n->keyword_rest) R("keyword_rest", n->keyword_rest);
746
+ break;
747
+ }
748
+ case PM_REQUIRED_PARAMETER_NODE: {
749
+ pm_required_parameter_node_t *n = (pm_required_parameter_node_t *)node;
750
+ N("RequiredParameterNode");
751
+ NAME("name", n->name);
752
+ break;
753
+ }
754
+ case PM_OPTIONAL_PARAMETER_NODE: {
755
+ pm_optional_parameter_node_t *n = (pm_optional_parameter_node_t *)node;
756
+ N("OptionalParameterNode");
757
+ NAME("name", n->name);
758
+ R("value", n->value);
759
+ break;
760
+ }
761
+ case PM_REST_PARAMETER_NODE: {
762
+ pm_rest_parameter_node_t *n = (pm_rest_parameter_node_t *)node;
763
+ N("RestParameterNode");
764
+ if (n->name) { NAME("name", n->name); }
765
+ break;
766
+ }
767
+ case PM_BLOCK_PARAMETER_NODE: {
768
+ pm_block_parameter_node_t *n = (pm_block_parameter_node_t *)node;
769
+ N("BlockParameterNode");
770
+ if (n->name) { NAME("name", n->name); }
771
+ break;
772
+ }
773
+ case PM_BLOCK_ARGUMENT_NODE: {
774
+ /* `&expr` in call argument position. Wraps the expression that
775
+ * provides the proc to forward (typically a LocalVariableReadNode
776
+ * for a `&block`-captured param, or a SymbolNode for `&:to_s`). */
777
+ pm_block_argument_node_t *n = (pm_block_argument_node_t *)node;
778
+ N("BlockArgumentNode");
779
+ R("expression", n->expression);
780
+ break;
781
+ }
782
+ case PM_BLOCK_LOCAL_VARIABLE_NODE: {
783
+ pm_block_local_variable_node_t *n = (pm_block_local_variable_node_t *)node;
784
+ N("BlockLocalVariableNode");
785
+ NAME("name", n->name);
786
+ break;
787
+ }
788
+ case PM_KEYWORD_REST_PARAMETER_NODE: {
789
+ pm_keyword_rest_parameter_node_t *n = (pm_keyword_rest_parameter_node_t *)node;
790
+ N("KeywordRestParameterNode");
791
+ if (n->name) { NAME("name", n->name); }
792
+ break;
793
+ }
794
+ case PM_REQUIRED_KEYWORD_PARAMETER_NODE: {
795
+ pm_required_keyword_parameter_node_t *n = (pm_required_keyword_parameter_node_t *)node;
796
+ N("RequiredKeywordParameterNode");
797
+ NAME("name", n->name);
798
+ break;
799
+ }
800
+ case PM_OPTIONAL_KEYWORD_PARAMETER_NODE: {
801
+ pm_optional_keyword_parameter_node_t *n = (pm_optional_keyword_parameter_node_t *)node;
802
+ N("OptionalKeywordParameterNode");
803
+ NAME("name", n->name);
804
+ R("value", n->value);
805
+ break;
806
+ }
807
+ case PM_PARENTHESES_NODE: {
808
+ pm_parentheses_node_t *n = (pm_parentheses_node_t *)node;
809
+ N("ParenthesesNode");
810
+ R("body", n->body);
811
+ break;
812
+ }
813
+ case PM_AND_NODE: {
814
+ pm_and_node_t *n = (pm_and_node_t *)node;
815
+ N("AndNode");
816
+ R("left", n->left);
817
+ R("right", n->right);
818
+ break;
819
+ }
820
+ case PM_OR_NODE: {
821
+ pm_or_node_t *n = (pm_or_node_t *)node;
822
+ N("OrNode");
823
+ R("left", n->left);
824
+ R("right", n->right);
825
+ break;
826
+ }
827
+ case PM_DEFINED_NODE: {
828
+ pm_defined_node_t *n = (pm_defined_node_t *)node;
829
+ N("DefinedNode");
830
+ R("value", n->value);
831
+ break;
832
+ }
833
+ case PM_SOURCE_LINE_NODE: {
834
+ N("SourceLineNode");
835
+ int32_t line = pm_newline_list_line(&g_parser->newline_list, node->location.start, g_parser->start_line);
836
+ I("start_line", (long long)line);
837
+ break;
838
+ }
839
+ case PM_SOURCE_FILE_NODE: {
840
+ /* `__FILE__`. Spinel inlines `require`/`require_relative` at parse
841
+ time so we cannot recover the per-call-site source file; we
842
+ always return the toplevel script path passed to spinel_parse,
843
+ documented in test/source_file.rb. The escaped form is cached
844
+ in g_source_file_escaped at init since it never changes. */
845
+ N("SourceFileNode");
846
+ emit_str(id, "content", g_source_file_escaped);
847
+ break;
848
+ }
849
+ case PM_SOURCE_ENCODING_NODE: {
850
+ /* `__ENCODING__`. CRuby returns an Encoding object; Spinel has
851
+ no Encoding runtime, so we return the canonical name as a
852
+ frozen string. All Spinel sources are UTF-8. */
853
+ N("SourceEncodingNode");
854
+ break;
855
+ }
856
+ case PM_IMPLICIT_NODE: {
857
+ /* Wraps an implicit value reference, e.g. the value side of a
858
+ hash-shorthand `{x:}`. Lowers to its inner value at the same
859
+ id slot so the codegen never sees the implicit wrapper. Covers
860
+ PM_IMPLICIT_NODE in any context (AssocNode value, kwarg
861
+ shorthand inside KeywordHashNode, future Prism evolutions). */
862
+ pm_implicit_node_t *n = (pm_implicit_node_t *)node;
863
+ node_counter--;
864
+ return flatten(n->value);
865
+ }
866
+ case PM_MISSING_NODE: {
867
+ /* Prism emits MissingNode as an error-recovery placeholder. main()
868
+ bails out before flatten() runs when parser.error_list is
869
+ non-empty, so reaching this case means Prism produced a
870
+ MissingNode without flagging an error -- a contract violation we
871
+ surface clearly rather than silently miscompile. */
872
+ fprintf(stderr, "spinel_parse: internal error: MissingNode reached flatten() at byte offset %td; parse error not in error_list\n",
873
+ node->location.start - g_parser->start);
874
+ exit(1);
875
+ }
876
+ case PM_SHAREABLE_CONSTANT_NODE: {
877
+ /* `# shareable_constant_value: literal` magic comment that wraps
878
+ a constant write. Spinel has no Ractor support, so the
879
+ shareability state is a no-op. We lower at parse time by
880
+ flattening the inner write directly into THIS node slot and
881
+ discarding the wrapper. Many later codegen scanner passes
882
+ look for ConstantWriteNode at the top level of statements;
883
+ lowering here lets all of them work without modification. */
884
+ pm_shareable_constant_node_t *n = (pm_shareable_constant_node_t *)node;
885
+ /* Re-flatten the inner write at *this* id by rewinding the counter. */
886
+ node_counter--;
887
+ return flatten(n->write);
888
+ }
889
+ case PM_SPLAT_NODE: {
890
+ pm_splat_node_t *n = (pm_splat_node_t *)node;
891
+ N("SplatNode");
892
+ R("expression", n->expression);
893
+ break;
894
+ }
895
+ case PM_SUPER_NODE: {
896
+ pm_super_node_t *n = (pm_super_node_t *)node;
897
+ N("SuperNode");
898
+ R("arguments", n->arguments);
899
+ break;
900
+ }
901
+ case PM_FORWARDING_SUPER_NODE:
902
+ N("ForwardingSuperNode");
903
+ break;
904
+ case PM_MULTI_WRITE_NODE: {
905
+ pm_multi_write_node_t *n = (pm_multi_write_node_t *)node;
906
+ N("MultiWriteNode");
907
+ A("lefts", &n->lefts);
908
+ if (n->rest) R("rest", n->rest);
909
+ A("rights", &n->rights);
910
+ R("value", n->value);
911
+ break;
912
+ }
913
+ case PM_IMPLICIT_REST_NODE:
914
+ N("ImplicitRestNode");
915
+ break;
916
+ case PM_LAMBDA_NODE: {
917
+ pm_lambda_node_t *n = (pm_lambda_node_t *)node;
918
+ N("LambdaNode");
919
+ if (n->parameters) {
920
+ if (PM_NODE_TYPE(n->parameters) == PM_BLOCK_PARAMETERS_NODE) {
921
+ pm_block_parameters_node_t *bp = (pm_block_parameters_node_t *)n->parameters;
922
+ if (bp->parameters) {
923
+ R("parameters", bp->parameters);
924
+ }
925
+ } else if (PM_NODE_TYPE(n->parameters) != PM_NUMBERED_PARAMETERS_NODE) {
926
+ R("parameters", n->parameters);
927
+ }
928
+ }
929
+ if (n->body) R("body", n->body);
930
+ break;
931
+ }
932
+ case PM_X_STRING_NODE: {
933
+ pm_x_string_node_t *n = (pm_x_string_node_t *)node;
934
+ N("XStringNode");
935
+ S("content", escape_pm_string(&n->unescaped));
936
+ break;
937
+ }
938
+ case PM_INTERPOLATED_X_STRING_NODE: {
939
+ pm_interpolated_x_string_node_t *n = (pm_interpolated_x_string_node_t *)node;
940
+ N("InterpolatedXStringNode");
941
+ A("parts", &n->parts);
942
+ break;
943
+ }
944
+ case PM_REGULAR_EXPRESSION_NODE: {
945
+ pm_regular_expression_node_t *n = (pm_regular_expression_node_t *)node;
946
+ N("RegularExpressionNode");
947
+ S("unescaped", escape_pm_string(&n->unescaped));
948
+ /* Emit Prism's regex flags so the codegen can pass /i, /x, /m
949
+ through to the engine. PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE=4,
950
+ _EXTENDED=8, _MULTI_LINE=16. */
951
+ I("flags", n->base.flags);
952
+ break;
953
+ }
954
+ case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: {
955
+ /* `/foo_#{x}/`. Same shape as InterpolatedStringNode -- carries
956
+ `parts` -- plus a flags integer matching RegularExpressionNode.
957
+ Codegen builds the pattern string via compile_interpolated and
958
+ feeds it to sp_re_runtime_compile at execution time. */
959
+ pm_interpolated_regular_expression_node_t *n = (pm_interpolated_regular_expression_node_t *)node;
960
+ N("InterpolatedRegularExpressionNode");
961
+ A("parts", &n->parts);
962
+ I("flags", n->base.flags);
963
+ break;
964
+ }
965
+ case PM_NUMBERED_REFERENCE_READ_NODE: {
966
+ pm_numbered_reference_read_node_t *n = (pm_numbered_reference_read_node_t *)node;
967
+ N("NumberedReferenceReadNode");
968
+ I("number", n->number);
969
+ break;
970
+ }
971
+ case PM_MATCH_WRITE_NODE: {
972
+ pm_match_write_node_t *n = (pm_match_write_node_t *)node;
973
+ N("MatchWriteNode");
974
+ R("call", n->call);
975
+ break;
976
+ }
977
+ case PM_MATCH_REQUIRED_NODE: {
978
+ /* Rightward assignment: `expr => var` (Ruby 3.0+). When the
979
+ pattern is a single LocalVariableTargetNode, this is just
980
+ `var = expr` and we lower it to a LocalVariableWriteNode so
981
+ the codegen reuses the regular assignment path. Full pattern
982
+ matching (array / hash patterns, pinned vars) is out of scope
983
+ and falls through to the unknown-node passthrough. */
984
+ pm_match_required_node_t *n = (pm_match_required_node_t *)node;
985
+ if (n->pattern && PM_NODE_TYPE_P(n->pattern, PM_LOCAL_VARIABLE_TARGET_NODE)) {
986
+ pm_local_variable_target_node_t *t = (pm_local_variable_target_node_t *)n->pattern;
987
+ N("LocalVariableWriteNode");
988
+ NAME("name", t->name);
989
+ R("value", n->value);
990
+ } else {
991
+ N("MatchRequiredNode");
992
+ R("value", n->value);
993
+ R("pattern", n->pattern);
994
+ }
995
+ break;
996
+ }
997
+ case PM_ALTERNATION_PATTERN_NODE: {
998
+ pm_alternation_pattern_node_t *n = (pm_alternation_pattern_node_t *)node;
999
+ N("AlternationPatternNode");
1000
+ R("left", n->left);
1001
+ R("right", n->right);
1002
+ break;
1003
+ }
1004
+ case PM_NUMBERED_PARAMETERS_NODE: {
1005
+ pm_numbered_parameters_node_t *n = (pm_numbered_parameters_node_t *)node;
1006
+ N("NumberedParametersNode");
1007
+ I("maximum", n->maximum);
1008
+ break;
1009
+ }
1010
+ case PM_ARGUMENTS_NODE: {
1011
+ pm_arguments_node_t *n = (pm_arguments_node_t *)node;
1012
+ N("ArgumentsNode");
1013
+ A("arguments", &n->arguments);
1014
+ break;
1015
+ }
1016
+ case PM_BLOCK_PARAMETERS_NODE: {
1017
+ pm_block_parameters_node_t *n = (pm_block_parameters_node_t *)node;
1018
+ N("BlockParametersNode");
1019
+ if (n->parameters) R("parameters", n->parameters);
1020
+ break;
1021
+ }
1022
+ case PM_IT_PARAMETERS_NODE:
1023
+ /* Ruby 3.4 implicit `it` is semantically `_1` — lower to a
1024
+ NumberedParametersNode so the codegen's existing
1025
+ NumberedParametersNode arity path (get_block_param) handles it
1026
+ transparently. The block body's `it` references separately
1027
+ become PM_IT_LOCAL_VARIABLE_READ_NODE, also lowered below. */
1028
+ N("NumberedParametersNode");
1029
+ I("maximum", 1);
1030
+ break;
1031
+ case PM_IT_LOCAL_VARIABLE_READ_NODE:
1032
+ /* `it` inside the block body. Lowered to a regular
1033
+ LocalVariableReadNode named "_1" so it pairs with the
1034
+ lowered NumberedParametersNode { maximum: 1 } above. */
1035
+ N("LocalVariableReadNode");
1036
+ S("name", escape_str((const uint8_t *)"_1", 2));
1037
+ break;
1038
+ case PM_INTERPOLATED_SYMBOL_NODE: {
1039
+ /* `:"foo_#{x}"`. Carries `parts` like InterpolatedStringNode;
1040
+ codegen builds the string the same way and uses it directly --
1041
+ Spinel treats dynamic symbols as their assembled string value
1042
+ since it doesn't intern non-literal symbols. */
1043
+ pm_interpolated_symbol_node_t *n = (pm_interpolated_symbol_node_t *)node;
1044
+ N("InterpolatedSymbolNode");
1045
+ A("parts", &n->parts);
1046
+ break;
1047
+ }
1048
+ case PM_REDO_NODE:
1049
+ /* `redo`. Re-run the current iteration of the enclosing loop
1050
+ without re-evaluating the loop guard or advancing the
1051
+ iterator. Codegen emits a labeled `goto` to a label installed
1052
+ at the top of the iteration body. */
1053
+ N("RedoNode");
1054
+ break;
1055
+ case PM_BACK_REFERENCE_READ_NODE: {
1056
+ /* `$&`, `$~`, `$'`, $`. Spinel populates sp_re_match_str / _pre /
1057
+ _post during regex matches alongside sp_re_captures (which the
1058
+ NumberedReferenceReadNode arm already reads). */
1059
+ pm_back_reference_read_node_t *n = (pm_back_reference_read_node_t *)node;
1060
+ N("BackReferenceReadNode");
1061
+ NAME("name", n->name);
1062
+ break;
1063
+ }
1064
+ case PM_MULTI_TARGET_NODE: {
1065
+ /* Nested LHS in destructuring multi-assign:
1066
+ `a, (b, c), d = 1, [2, 3], 4`. The inner (b, c) parenthesized
1067
+ group becomes a MultiTargetNode that recursively unpacks its
1068
+ slot of the RHS into the inner targets. */
1069
+ pm_multi_target_node_t *n = (pm_multi_target_node_t *)node;
1070
+ N("MultiTargetNode");
1071
+ A("lefts", &n->lefts);
1072
+ if (n->rest) R("rest", n->rest);
1073
+ A("rights", &n->rights);
1074
+ break;
1075
+ }
1076
+ case PM_EMBEDDED_VARIABLE_NODE: {
1077
+ /* `"foo #@bar"` shorthand for `"foo #{@bar}"`. The cleanest
1078
+ implementation is parser-side lowering: synthesize an
1079
+ EmbeddedStatementsNode wrapping a StatementsNode whose single
1080
+ body element is the variable read. The existing interpolation
1081
+ path then handles it without any codegen change.
1082
+
1083
+ Same lowering trick as PM_IT_LOCAL_VARIABLE_READ_NODE -- emit
1084
+ a different node type at the same `id` slot so parent walks
1085
+ (parts list of the surrounding InterpolatedString) keep the
1086
+ slot unchanged. The wrapped StatementsNode gets a fresh id
1087
+ allocated via node_counter++. */
1088
+ pm_embedded_variable_node_t *n = (pm_embedded_variable_node_t *)node;
1089
+ N("EmbeddedStatementsNode");
1090
+ int var_id = flatten(n->variable);
1091
+ int stmts_id = node_counter++;
1092
+ out_add("N %d StatementsNode", stmts_id);
1093
+ out_add("A %d body %d", stmts_id, var_id);
1094
+ out_add("R %d statements %d", id, stmts_id);
1095
+ break;
1096
+ }
1097
+ case PM_ALIAS_METHOD_NODE: {
1098
+ /* `alias new old` -- compile-time method-name aliasing inside a
1099
+ class body. new_name and old_name are nodes representing the
1100
+ names (typically SymbolNode literals; InterpolatedSymbolNode is
1101
+ tolerated and silently skipped by the codegen helper). Spinel
1102
+ registers a duplicate method-table entry under the new name
1103
+ pointing to the same body, so dispatch on `.greet` lands on the
1104
+ same C function as `.hello`. */
1105
+ pm_alias_method_node_t *n = (pm_alias_method_node_t *)node;
1106
+ N("AliasMethodNode");
1107
+ R("new_name", n->new_name);
1108
+ R("old_name", n->old_name);
1109
+ break;
1110
+ }
1111
+ case PM_POST_EXECUTION_NODE: {
1112
+ /* `END { ... }`. CRuby runs END blocks in REVERSE registration
1113
+ order at program exit. Spinel emits each as a static C
1114
+ function and registers them via atexit() at main() startup --
1115
+ atexit naturally invokes handlers LIFO, matching CRuby. */
1116
+ pm_post_execution_node_t *n = (pm_post_execution_node_t *)node;
1117
+ N("PostExecutionNode");
1118
+ R("statements", n->statements);
1119
+ break;
1120
+ }
1121
+ case PM_PRE_EXECUTION_NODE: {
1122
+ /* `BEGIN { ... }`. CRuby runs all BEGIN blocks in source order
1123
+ BEFORE any other top-level statements. Spinel collects the
1124
+ bodies during a pre-pass and emits them at the very top of
1125
+ main() in source-encounter order. */
1126
+ pm_pre_execution_node_t *n = (pm_pre_execution_node_t *)node;
1127
+ N("PreExecutionNode");
1128
+ R("statements", n->statements);
1129
+ break;
1130
+ }
1131
+ case PM_UNDEF_NODE: {
1132
+ /* `undef foo, bar` inside a class body. CRuby raises NoMethodError
1133
+ at runtime when an undef'd method is called; Spinel's AOT model
1134
+ resolves dispatch at compile time, so we record the undefs but
1135
+ leave compile-time enforcement of "calling an undef'd method
1136
+ fails" to a future pass. */
1137
+ pm_undef_node_t *n = (pm_undef_node_t *)node;
1138
+ N("UndefNode");
1139
+ A("names", &n->names);
1140
+ break;
1141
+ }
1142
+ case PM_ALIAS_GLOBAL_VARIABLE_NODE: {
1143
+ /* `alias $copy $orig` -- compile-time gvar aliasing. The
1144
+ new_name and old_name slots are GlobalVariableReadNodes whose
1145
+ `name` field carries the literal $-prefixed name. Spinel
1146
+ resolves $copy to $orig everywhere the alias is in scope, so
1147
+ the C output uses one storage slot for both. */
1148
+ pm_alias_global_variable_node_t *n = (pm_alias_global_variable_node_t *)node;
1149
+ N("AliasGlobalVariableNode");
1150
+ R("new_name", n->new_name);
1151
+ R("old_name", n->old_name);
1152
+ break;
1153
+ }
1154
+ default: {
1155
+ /* Previously emitted UnknownNode_<n> which silently degraded to
1156
+ "0" in codegen. Now emit a hard-error sentinel carrying the
1157
+ Prism node kind name (in human-friendly Ruby vocabulary) + the
1158
+ source line so codegen refuses to compile and tells the user
1159
+ exactly what's wrong. */
1160
+ char pretty[128];
1161
+ size_t plen = prism_kind_to_pascal(pm_node_type_to_str(t), pretty, sizeof(pretty));
1162
+ int32_t line = pm_newline_list_line(&g_parser->newline_list, node->location.start, g_parser->start_line);
1163
+
1164
+ N("UnsupportedNode");
1165
+ char *kind_e = escape_str((const uint8_t *)pretty, plen);
1166
+ emit_str(id, "kind", kind_e);
1167
+ free(kind_e);
1168
+ emit_int(id, "source_line", (long long)line);
1169
+ break;
1170
+ }
1171
+ }
1172
+
1173
+ #undef N
1174
+ #undef S
1175
+ #undef I
1176
+ #undef F
1177
+ #undef R
1178
+ #undef A
1179
+ #undef NAME
1180
+
1181
+ return id;
1182
+ }
1183
+
1184
+ /* ---- require_relative resolution ---- */
1185
+ static char *read_file(const char *path) {
1186
+ FILE *f = fopen(path, "rb");
1187
+ if (!f) return NULL;
1188
+ fseek(f, 0, SEEK_END);
1189
+ long len = ftell(f);
1190
+ fseek(f, 0, SEEK_SET);
1191
+ char *buf = malloc(len + 1);
1192
+ size_t nread = fread(buf, 1, len, f);
1193
+ buf[nread] = '\0';
1194
+ fclose(f);
1195
+ return buf;
1196
+ }
1197
+
1198
+ /* Track files already inlined so duplicate requires/require_relatives in
1199
+ different files don't re-emit (and re-define structs/classes) the same
1200
+ content. Dynamic so we don't silently drop entries on large projects. */
1201
+ static char **sp_included_paths = NULL;
1202
+ static int sp_included_count = 0;
1203
+ static int sp_included_cap = 0;
1204
+
1205
+ /* Resolve a path to its canonical form for dedup. realpath() returns NULL
1206
+ on missing files; in that case fall back to the literal path. */
1207
+ static char *sp_canonical_path(const char *path) {
1208
+ #ifdef _WIN32
1209
+ char *real = _fullpath(NULL, path, 0);
1210
+ #else
1211
+ char *real = realpath(path, NULL);
1212
+ #endif
1213
+ return real ? real : strdup(path);
1214
+ }
1215
+
1216
+ static int sp_path_already_included(const char *canonical) {
1217
+ for (int i = 0; i < sp_included_count; i++) {
1218
+ if (strcmp(sp_included_paths[i], canonical) == 0) return 1;
1219
+ }
1220
+ return 0;
1221
+ }
1222
+
1223
+ static void sp_mark_path_included(const char *canonical) {
1224
+ if (sp_included_count >= sp_included_cap) {
1225
+ sp_included_cap = sp_included_cap == 0 ? 16 : sp_included_cap * 2;
1226
+ sp_included_paths = (char **)realloc(sp_included_paths,
1227
+ sizeof(char *) * sp_included_cap);
1228
+ }
1229
+ sp_included_paths[sp_included_count++] = strdup(canonical);
1230
+ }
1231
+
1232
+ /* Free the included-paths table at end of run. The process is short-lived,
1233
+ so this matters mostly for tools (leak checkers, embedders) that
1234
+ scrutinise end-of-run state. */
1235
+ static void sp_includes_free(void) {
1236
+ for (int i = 0; i < sp_included_count; i++) {
1237
+ free(sp_included_paths[i]);
1238
+ }
1239
+ free(sp_included_paths);
1240
+ sp_included_paths = NULL;
1241
+ sp_included_count = 0;
1242
+ sp_included_cap = 0;
1243
+ }
1244
+
1245
+ /* Simple require_relative resolver: replace lines matching
1246
+ require_relative "path" with the file content. Files that have
1247
+ already been included once are silently skipped on subsequent
1248
+ requires (matching Ruby's load-once semantics). */
1249
+ static char *resolve_requires(const char *source, const char *source_path) {
1250
+ /* Get base directory */
1251
+ char *path_copy = strdup(source_path);
1252
+ char *dir = strdup(path_copy);
1253
+ /* Find last / */
1254
+ char *slash = strrchr(dir, '/');
1255
+ if (slash) *slash = '\0';
1256
+ else { free(dir); dir = strdup("."); }
1257
+ free(path_copy);
1258
+
1259
+ char *result = strdup(source);
1260
+ char *pos;
1261
+ char *scan_from = result;
1262
+ while ((pos = strstr(scan_from, "require_relative")) != NULL) {
1263
+ /* Check it's at start of line. If the match is mid-line (e.g.
1264
+ the word appears in a comment or string), advance past it and
1265
+ keep scanning the rest of the file — don't abort the whole
1266
+ loop, since later lines may have legitimate require_relative
1267
+ statements. */
1268
+ if (pos != result && *(pos - 1) != '\n') {
1269
+ scan_from = pos + 1;
1270
+ continue;
1271
+ }
1272
+ char *line_end = strchr(pos, '\n');
1273
+ if (!line_end) line_end = pos + strlen(pos);
1274
+
1275
+ /* Extract quoted path */
1276
+ char *q1 = strchr(pos, '"');
1277
+ char *q2 = strchr(pos, '\'');
1278
+ char quote_char;
1279
+ char *start;
1280
+ if (q1 && q1 < line_end && (!q2 || q1 < q2)) {
1281
+ quote_char = '"';
1282
+ start = q1 + 1;
1283
+ } else if (q2 && q2 < line_end) {
1284
+ quote_char = '\'';
1285
+ start = q2 + 1;
1286
+ } else { scan_from = pos + 1; continue; }
1287
+
1288
+ char *end = strchr(start, quote_char);
1289
+ if (!end || end > line_end) { scan_from = pos + 1; continue; }
1290
+
1291
+ size_t path_len = end - start;
1292
+ char rel_path[512];
1293
+ snprintf(rel_path, sizeof(rel_path), "%.*s", (int)path_len, start);
1294
+
1295
+ /* Build full path */
1296
+ char full_path[1024];
1297
+ snprintf(full_path, sizeof(full_path), "%s/%s", dir, rel_path);
1298
+ {
1299
+ size_t fl = strlen(full_path);
1300
+ if (fl < sizeof(full_path) - 4 && (fl < 3 || strcmp(full_path + fl - 3, ".rb") != 0))
1301
+ strcat(full_path, ".rb");
1302
+ }
1303
+
1304
+ char *canonical = sp_canonical_path(full_path);
1305
+ char *content;
1306
+ if (sp_path_already_included(canonical)) {
1307
+ /* Already inlined once -- replace require with empty content */
1308
+ content = strdup("# require_relative skipped (already included)");
1309
+ free(canonical);
1310
+ } else {
1311
+ sp_mark_path_included(canonical);
1312
+ content = read_file(full_path);
1313
+ if (!content) {
1314
+ content = strdup("# require_relative not found");
1315
+ } else {
1316
+ /* Recursively resolve */
1317
+ char *resolved = resolve_requires(content, full_path);
1318
+ free(content);
1319
+ content = resolved;
1320
+ }
1321
+ free(canonical);
1322
+ }
1323
+
1324
+ /* Replace the line */
1325
+ size_t line_len = (line_end - pos) + ((*line_end == '\n') ? 1 : 0);
1326
+ size_t content_len = strlen(content);
1327
+ size_t result_len = strlen(result);
1328
+ size_t before_len = pos - result;
1329
+
1330
+ char *new_result = malloc(result_len - line_len + content_len + 2);
1331
+ memcpy(new_result, result, before_len);
1332
+ memcpy(new_result + before_len, content, content_len);
1333
+ if (content_len > 0 && content[content_len - 1] != '\n')
1334
+ new_result[before_len + content_len++] = '\n';
1335
+ memcpy(new_result + before_len + content_len, pos + line_len, result_len - before_len - line_len + 1);
1336
+
1337
+ free(result);
1338
+ result = new_result;
1339
+ /* Buffer reallocated; restart scan from the top of the new buffer. */
1340
+ scan_from = result;
1341
+ free(content);
1342
+ }
1343
+ free(dir);
1344
+ return result;
1345
+ }
1346
+
1347
+ /* ---- Plain require resolution ---- */
1348
+ static char *resolve_plain_requires(char *source, const char *exe_path) {
1349
+ /* Find lib/ directory relative to this executable */
1350
+ char lib_dir[1024];
1351
+ strncpy(lib_dir, exe_path, sizeof(lib_dir) - 1);
1352
+ char *slash = strrchr(lib_dir, '/');
1353
+ if (slash) *slash = '\0';
1354
+ else strcpy(lib_dir, ".");
1355
+ strcat(lib_dir, "/lib");
1356
+
1357
+ char *result = source;
1358
+ char *pos;
1359
+ while ((pos = strstr(result, "\nrequire ")) != NULL ||
1360
+ (pos == NULL && result == source && strncmp(result, "require ", 8) == 0 && (pos = result))) {
1361
+ if (pos != result) pos++; /* skip \n */
1362
+ if (pos != result && *(pos - 1) != '\n') break;
1363
+ char *line_end = strchr(pos, '\n');
1364
+ if (!line_end) line_end = pos + strlen(pos);
1365
+
1366
+ /* Must be: require "name" or require 'name' */
1367
+ char *q1 = strchr(pos + 7, '"');
1368
+ char *q2 = strchr(pos + 7, '\'');
1369
+ char *start; char quote_char;
1370
+ if (q1 && q1 < line_end && (!q2 || q1 < q2)) { quote_char = '"'; start = q1 + 1; }
1371
+ else if (q2 && q2 < line_end) { quote_char = '\''; start = q2 + 1; }
1372
+ else break;
1373
+ char *end = strchr(start, quote_char);
1374
+ if (!end || end > line_end) break;
1375
+
1376
+ char lib_name[256];
1377
+ snprintf(lib_name, sizeof(lib_name), "%.*s", (int)(end - start), start);
1378
+ char lib_path[1024];
1379
+ snprintf(lib_path, sizeof(lib_path), "%s/%s", lib_dir, lib_name);
1380
+ {
1381
+ size_t fl = strlen(lib_path);
1382
+ if (fl < sizeof(lib_path) - 4 && (fl < 3 || strcmp(lib_path + fl - 3, ".rb") != 0))
1383
+ strcat(lib_path, ".rb");
1384
+ }
1385
+
1386
+ /* Same dedup as resolve_requires: a file pulled in via plain `require`
1387
+ must not be re-inlined if a previous `require` or `require_relative`
1388
+ already pulled it. Otherwise mixing the two forms for the same lib
1389
+ still produces struct-redefinition errors. */
1390
+ char *canonical = sp_canonical_path(lib_path);
1391
+ char *content;
1392
+ if (sp_path_already_included(canonical)) {
1393
+ content = strdup("# require skipped (already included)");
1394
+ free(canonical);
1395
+ } else {
1396
+ sp_mark_path_included(canonical);
1397
+ free(canonical);
1398
+ content = read_file(lib_path);
1399
+ if (!content) {
1400
+ content = strdup("# require not resolved");
1401
+ } else {
1402
+ char *resolved = resolve_requires(content, lib_path);
1403
+ free(content);
1404
+ content = resolved;
1405
+ }
1406
+ }
1407
+
1408
+ size_t line_len = (line_end - pos) + ((*line_end == '\n') ? 1 : 0);
1409
+ size_t content_len = strlen(content);
1410
+ size_t result_len = strlen(result);
1411
+ size_t before_len = pos - result;
1412
+ char *new_result = malloc(result_len - line_len + content_len + 2);
1413
+ memcpy(new_result, result, before_len);
1414
+ memcpy(new_result + before_len, content, content_len);
1415
+ if (content_len > 0 && content[content_len - 1] != '\n')
1416
+ new_result[before_len + content_len++] = '\n';
1417
+ memcpy(new_result + before_len + content_len, pos + line_len, result_len - before_len - line_len + 1);
1418
+ free(result);
1419
+ result = new_result;
1420
+ free(content);
1421
+ }
1422
+ return result;
1423
+ }
1424
+
1425
+ /* ---- Syntax sugar rewriting ---- */
1426
+ static char *rewrite_syntax_sugar(char *source) {
1427
+ /* Rewrite .send(:method, args) → .method(args) */
1428
+ /* Rewrite &:symbol → { |_spx| _spx.symbol } */
1429
+ size_t len = strlen(source);
1430
+ size_t cap = len * 2 + 256;
1431
+ char *out = malloc(cap);
1432
+ size_t oi = 0;
1433
+ size_t i = 0;
1434
+
1435
+ #define OUT_CHAR(c) do { if (oi >= cap - 1) { cap *= 2; out = realloc(out, cap); } out[oi++] = (c); } while(0)
1436
+ #define OUT_STR(s) do { const char *_s = (s); while (*_s) { OUT_CHAR(*_s); _s++; } } while(0)
1437
+
1438
+ while (i < len) {
1439
+ /* .send(:symbol ...) */
1440
+ if (i + 7 < len && strncmp(source + i, ".send(:", 7) == 0) {
1441
+ i += 7; /* skip .send(: */
1442
+ /* Extract method name */
1443
+ size_t ns = i;
1444
+ while (i < len && (source[i] == '_' || (source[i] >= 'a' && source[i] <= 'z') ||
1445
+ (source[i] >= 'A' && source[i] <= 'Z') || (source[i] >= '0' && source[i] <= '9') ||
1446
+ source[i] == '?' || source[i] == '!' || source[i] == '+' || source[i] == '-' ||
1447
+ source[i] == '*' || source[i] == '/' || source[i] == '<' || source[i] == '>' ||
1448
+ source[i] == '=' || source[i] == '&' || source[i] == '|' || source[i] == '^' ||
1449
+ source[i] == '~' || source[i] == '%')) i++;
1450
+ size_t name_len = i - ns;
1451
+ if (name_len > 0) {
1452
+ OUT_CHAR('.');
1453
+ size_t k; for (k = 0; k < name_len; k++) OUT_CHAR(source[ns + k]);
1454
+ /* Skip optional comma + space, then copy remaining args until ) */
1455
+ if (i < len && source[i] == ')') {
1456
+ i++; /* no args */
1457
+ } else if (i < len && source[i] == ',') {
1458
+ i++; /* skip comma */
1459
+ while (i < len && source[i] == ' ') i++;
1460
+ OUT_CHAR('(');
1461
+ /* Copy args until matching ) */
1462
+ int depth = 1;
1463
+ while (i < len && depth > 0) {
1464
+ if (source[i] == '(') depth++;
1465
+ else if (source[i] == ')') { depth--; if (depth == 0) { i++; break; } }
1466
+ OUT_CHAR(source[i]); i++;
1467
+ }
1468
+ OUT_CHAR(')');
1469
+ }
1470
+ continue;
1471
+ }
1472
+ /* Failed to parse, output original */
1473
+ OUT_STR(".send(:");
1474
+ continue;
1475
+ }
1476
+ /* (&:symbol) → { |_spx| _spx.symbol } — also remove enclosing parens */
1477
+ if (i + 2 < len && source[i] == '&' && source[i + 1] == ':') {
1478
+ /* Check if preceded by ( and remove it */
1479
+ int had_paren = 0;
1480
+ if (oi > 0 && out[oi - 1] == '(') { oi--; had_paren = 1; }
1481
+ i += 2;
1482
+ size_t ns = i;
1483
+ while (i < len && (source[i] == '_' || (source[i] >= 'a' && source[i] <= 'z') ||
1484
+ (source[i] >= 'A' && source[i] <= 'Z') || (source[i] >= '0' && source[i] <= '9') ||
1485
+ source[i] == '?' || source[i] == '!')) i++;
1486
+ size_t name_len = i - ns;
1487
+ if (name_len > 0) {
1488
+ /* Skip closing paren if we removed opening */
1489
+ if (had_paren && i < len && source[i] == ')') i++;
1490
+ OUT_STR(" { |_spx| _spx.");
1491
+ size_t k; for (k = 0; k < name_len; k++) OUT_CHAR(source[ns + k]);
1492
+ OUT_STR(" }");
1493
+ continue;
1494
+ }
1495
+ if (had_paren) OUT_CHAR('('); /* restore if failed */
1496
+ OUT_STR("&:");
1497
+ continue;
1498
+ }
1499
+ OUT_CHAR(source[i]);
1500
+ i++;
1501
+ }
1502
+ out[oi] = '\0';
1503
+ free(source);
1504
+ return out;
1505
+ #undef OUT_CHAR
1506
+ #undef OUT_STR
1507
+ }
1508
+
1509
+ /* ---- Main ---- */
1510
+ int main(int argc, char **argv) {
1511
+ if (argc < 2) {
1512
+ fprintf(stderr, "Usage: spinel_parse input.rb [output.ast]\n");
1513
+ return 1;
1514
+ }
1515
+
1516
+ const char *source_file = argv[1];
1517
+ char *source = read_file(source_file);
1518
+ if (!source) {
1519
+ fprintf(stderr, "spinel_parse: cannot open '%s'\n", source_file);
1520
+ return 1;
1521
+ }
1522
+
1523
+ /* Resolve require_relative and plain require */
1524
+ char *resolved = resolve_requires(source, source_file);
1525
+ free(source);
1526
+ source = resolve_plain_requires(resolved, argv[0]);
1527
+ source = rewrite_syntax_sugar(source);
1528
+
1529
+ size_t source_len = strlen(source);
1530
+
1531
+ /* Parse with Prism */
1532
+ pm_parser_t parser;
1533
+ pm_parser_init(&parser, (const uint8_t *)source, source_len, NULL);
1534
+ pm_node_t *root = pm_parse(&parser);
1535
+
1536
+ if (parser.error_list.size > 0) {
1537
+ fprintf(stderr, "Parse errors in '%s':\n", source_file);
1538
+ pm_diagnostic_t *diag;
1539
+ for (diag = (pm_diagnostic_t *)parser.error_list.head; diag; diag = (pm_diagnostic_t *)diag->node.next) {
1540
+ fprintf(stderr, " %s\n", diag->message);
1541
+ }
1542
+ pm_node_destroy(&parser, root);
1543
+ pm_parser_free(&parser);
1544
+ free(source);
1545
+ return 1;
1546
+ }
1547
+
1548
+ g_parser = &parser;
1549
+ g_source_file = source_file;
1550
+ g_source_file_escaped = escape_str((const uint8_t *)g_source_file, strlen(g_source_file));
1551
+
1552
+ /* Flatten AST to text */
1553
+ lines = NULL;
1554
+ line_count = 0;
1555
+ line_cap = 0;
1556
+ node_counter = 0;
1557
+
1558
+ int root_id = flatten(root);
1559
+
1560
+ /* Output */
1561
+ FILE *out = stdout;
1562
+ if (argc >= 3) {
1563
+ out = fopen(argv[2], "wb");
1564
+ if (!out) {
1565
+ fprintf(stderr, "spinel_parse: cannot write '%s'\n", argv[2]);
1566
+ return 1;
1567
+ }
1568
+ }
1569
+
1570
+ fprintf(out, "ROOT %d\n", root_id);
1571
+ for (int i = 0; i < line_count; i++) {
1572
+ fprintf(out, "%s\n", lines[i]);
1573
+ free(lines[i]);
1574
+ }
1575
+ free(lines);
1576
+
1577
+ if (out != stdout) fclose(out);
1578
+
1579
+ pm_node_destroy(&parser, root);
1580
+ pm_parser_free(&parser);
1581
+ free(source);
1582
+ free(g_source_file_escaped); /* paired with the escape_str() in init */
1583
+ g_source_file_escaped = NULL;
1584
+ sp_includes_free();
1585
+ return 0;
1586
+ }